代码之家  ›  专栏  ›  技术社区  ›  BattleTested_закалённый в бою Fritz R.

C-为什么杂注包(1)将6位结构成员视为8位?

  •  0
  • BattleTested_закалённый в бою Fritz R.  · 技术社区  · 6 年前

    我被困住了 #pragma pack(1) 定义时的错误行为 6-bit 字段并假定它为 8-bit . 我读过 this question

    Visual Studio 2012 我定义如下 struct 为了节省 Base64 字符:

    #pragma pack(1)
    struct BASE64 {
        CHAR    cChar1 : 6;
        CHAR    cChar2 : 6;
        CHAR    cChar3 : 6;
        CHAR    cChar4 : 6;
    };
    

    sizeof ,但结果不是我所期望的:

    printf("%d", sizeof(BASE64));      // should print 3
    

    结果: 4

    我本来以为 3 6 * 4 = 24 ,所以 24 比特是

    我用它测试的事件 1-bit

    #pragma pack(1)
    struct BASE64 {
        CHAR    cChar1 : 2;
        CHAR    cChar2 : 2;
        CHAR    cChar3 : 2;
        CHAR    cChar4 : 2;
    };
    

    实际上,为什么 6位 假设 8位 具有 ?

    3 回复  |  直到 6 年前
        1
  •  6
  •   paxdiablo    6 年前

    #pragma pack 通常按字节边界打包,而不是按位边界打包。是为了防止填充物的插入 在要保持压缩的字段之间。从 Microsoft's documentation (因为你提供了 winapi 加上我的强调):

    n (可选):指定值,在 用于包装。

    当您试图让位字段跨越字节边界时,实现如何处理位字段是由实现定义的。来自C11标准(secion 6.7.2.1 Structure and union specifiers /11 ,再次强调):

    如果剩余空间不足,则实现定义是将不适合的位字段放入下一个单元还是重叠相邻单元。

    More of the MS documentation 指出这种具体行为:

    如果整数类型的大小相同,并且下一个位字段在不越过位字段的公共对齐要求所施加的边界的情况下适合当前分配单元,则相邻位字段被打包到相同的1、2或4字节分配单元中。

        2
  •  2
  •   CiaPan    6 年前

    简单的答案是:这不是 错误的行为 .

    打包尝试以字节为单位放置单独的数据块,但不能在一个8位字节中打包两个6位块。所以编译器将它们放在单独的字节中,可能是因为访问一个字节来检索或存储6位数据比访问两个连续字节和处理一个字节的某个尾随部分和另一个字节的某个前导部分更容易。

    那么远 . 不管怎么说,大小优化通常会缩短代码,而不是数据(据我所知,但我不是专家,我很可能错在这里)。

        3
  •  2
  •   paxdiablo    6 年前

    在第一个示例中,没有足够的可用位 CHAR 两者兼得 cChar1 cChar2 当它们是6位的时候,所以 cChar2号 下一个必须进去 在记忆中。与相同 cChar3 cChar4 . 所以为什么 BASE64

      (6 bits + 2 bits padding) = 8 bits
    + (6 bits + 2 bits padding) = 8 bits
    + (6 bits + 2 bits padding) = 8 bits
    + 6 bits
    - - - - - - - - - - 
    = 30 bits
    = needs 4 bytes
    

    在第二个例子中,在 持有所有 cChar1号 cChar4号 当它们各1位时。所以为什么 基数64

      1 bit
    + 1 bit
    + 1 bit
    + 1 bit
    - - - - - - - - - - 
    = 4 bits
    = needs 1 byte