代码之家  ›  专栏  ›  技术社区  ›  Laz

如何用C表示位信息?

c
  •  5
  • Laz  · 技术社区  · 14 年前

    我需要在C中存储一个0-15之间的值,4位就足够了。我怎么能有一个4位的变量呢?空间在这里是个限制

    6 回复  |  直到 14 年前
        1
  •  7
  •   kbrimington    14 年前

    考虑使用 char . 是的,它是8位的,但是你可以使用位移位运算符( << >> )将值存储在其他4位中。

    根据下面的评论 unsigned char 烧焦

        2
  •  4
  •   Will A    14 年前

    你可以使用 bitfield 但是,要存储4位,除非在一个结构中有几个相邻的位,否则将值存储在一个字节中不会节省任何空间。

        3
  •  3
  •   Karl Bielefeldt    14 年前

    你不能真的有一个4位变量,但是你可以有8位变量来存储两个4位值,但是你必须用一个临时变量来访问它们,这意味着除非你有两个以上的变量,否则你不会节省任何空间:

    uint8_t var_both;
    uint8_t temp = (var_both >> 4) & 0x0F; // For first value
    temp = var_both & 0x0F; // For second value
    
        4
  •  2
  •   Simon    14 年前

    正如Chris Lutz所指定的,您可以通过添加冒号和冒号的大小来定义变量使用的位数: unsigned char myOneBitVariable:1; 极其困难 这是和 你为什么要避免 .

    大多数现代编译器都会在结构中对齐变量的空间。目前最普遍的情况是4字节甚至8字节,但这因平台和编译器而异。某些编译器允许您指定数据及其成员的对齐方式。在GCC上,关键字是 __attribute__((aligned(x))) __declspec(align(x)) . 在大多数情况下,您还需要指定编译器应该打包多少结构。MSVC拥有 #pragma pack(x) 指令: http://msdn.microsoft.com/en-us/library/2e70t5y1(VS.80).aspx . 您还可以在此处阅读有关MSVC对齐的信息: http://msdn.microsoft.com/en-us/library/83ythb65(VS.80).aspx __attribute__ ((__packed__) ,您可能需要四处搜索。 使用Microsoft的编译器无法提供所需内容的示例:

    
    #ifndef _MSC_VER
    #error This alignment solution / packing solution is only valid on MSC
    #endif /* ifndef _MSC_VER */
    
    #define M_ALIGN(x)    __declspec(align(x))
    
    struct S64Bits
    {
        unsigned char MyOneBitVariable:1;
        int My32BitInt;
    };
    
    // MSVC specific implementation of data-packing in a type.
    #pragma pack(1)
    struct S32Bits
    {
        D_ALIGN(1) int My16BitVariable:16;
        D_ALIGN(1) unsigned char Padding8Bits;
        D_ALIGN(1) unsigned char MyOneBitVariable1:1;
        D_ALIGN(1) unsigned char MyOneBitVariable2:1;
        D_ALIGN(1) unsigned char MyOneBitVariable3:1;
        D_ALIGN(1) unsigned char MyOneBitVariable4:1;
        D_ALIGN(1) unsigned char MyFourBitVariable:4;
    };
    #pragma pack(pop)
    

    'sizeof(s64位)'应该是8,实际上是这样“sizeof(s32位)”应为4, 不是的 . 在msvc上,后者是6个字节。该行为也是编译器特定的,并且通常具有编译器唯一的指令。这种行为几乎不会给你想要的。我经常使用宏来确保我要求具有一定大小的结构确实是:

    
    #define TEST_TYPE_SIZE(Type, Size) assert(sizeof(Type) == Size);
    

    我将在我的所有数据类型下面使用它,在这里我尝试指定它们的确切大小。然而,依赖sizeof(mystructure)以外的任何大小的结构进行编码很可能会导致难以调试的错误。对齐编译器指令最适合用于将数据与缓存线大小和类似的效率问题对齐。

    Karl Bielefeldt提供了一个很好的自然解决方案,可以使用位移位操作将4位值存储到uint8中,而不用这些操作。

        5
  •  0
  •   Chris Lutz    14 年前

    半字节的术语是半字节。所以这里:

    struct two_nibbles {
      unsigned a :4;
      unsigned b :4;
    }
    

    你必须给你的两个变量命名 x.a x.b (但是改变了 x 但你会节省一点空间。不过,你可能想检查一下-我想编译器会确保 sizeof(struct two_nibbles) == sizeof(char)

        6
  •  0
  •   anon anon    14 年前

    你有没有想过要取4位值的地址?如果是这样,您需要将它们存储在“适当”的数据类型中,例如char。