C++ struct语法"a:b"是什么意思

Kra*_*kos 28 c++ syntax struct data-structures

如果我有一个C++结构,定义一个64位数据字,如..

struct SMyDataWord
{
    int Name : 40;
    int Colour : 24;
};
Run Code Online (Sandbox Code Playgroud)

: 40语法意味着什么......是否意味着前40位是为Name保留的,剩下的24位是为Color设置的?

这就是它似乎被使用的方式,但我以前没遇到它.

dir*_*tly 21

从C继承的Name位域是40位宽,Colour是24位宽.因此,您的结构至少有64位.在我的系统上,64位将是8个字节.

  • 为了迂腐,一个字节中的位数是依赖于实现的(参见C,C++标准之一).这是由'limits'标题中的CHAR_BIT宏给出的. (12认同)
  • 什么系统将64位不是8字节? (8认同)
  • 一些 IBM 大型机有 9 位字节,IIRC。 (4认同)
  • *至少 64*?不准确?你的意思是结构可能占用超过 64 位吗? (2认同)

小智 10

这里sizeof很好地展示了幕后发生的事情:

#include <iostream>
#include <climits>

struct bc_1 {
   int a : 1;
   int b : 1;
};

struct bc_2 {
   int a : 31;
   int b : 1;
};

struct bc_3 {
   int a : 32;
   int b : 1;
};

struct bc_4 {
   int a : 31;
   int b : 2;
};

struct bc_5 {
   int a : 32;
   int b : 32;
};

struct bc_6 {
   int a : 40;
   int b : 32;
};

struct bc_7 {
   int a : 63;
   int b : 1;
};

int main(int argc, char * argv[]) {
    std::cout << "CHAR_BIT = " << CHAR_BIT;
    std::cout << " => sizeof(int) = " << sizeof(int) << std::endl;

    std::cout << "1,  1:  " << sizeof(struct bc_1) << std::endl;
    std::cout << "31, 1:  " << sizeof(struct bc_2) << std::endl;
    std::cout << "32, 1:  " << sizeof(struct bc_3) << std::endl;
    std::cout << "31, 2:  " << sizeof(struct bc_4) << std::endl;
    std::cout << "32, 32: " << sizeof(struct bc_5) << std::endl;
    std::cout << "40, 32: " << sizeof(struct bc_6) << std::endl;
    std::cout << "63, 1:  " << sizeof(struct bc_7) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

接下来的内容取决于您的编译器和操作系统,也可能取决于您的硬件。在带有 gcc-7(a CHAR_BIT= 8,32 位int(即 64 位的一半longsizeof(int)= 4)的macOS 上,这是我看到的输出:

CHAR_BIT = 8 => sizeof(int) = 4
1,  1:  4
31, 1:  4
32, 1:  8
31, 2:  8
32, 32: 8
40, 32: 12
63, 1:  8
Run Code Online (Sandbox Code Playgroud)

这告诉我们几件事情:如果int类型的两个字段都适合一个int(即上面示例中的 32 位),编译器只分配一个int值的内存(bc_1bc_2)。有一次,单个int不能再容纳位域,我们添加第二个(bc_3bc_4)。请注意,这bc_5是在容量。

有趣的是,我们可以“选择”比允许的更多的位。见bc_6。这里 g++-7 给出了警告:

bitfields.cpp::30:13: warning: width of 'bc_6::a' exceeds its type
     int a : 40;
             ^~
Run Code Online (Sandbox Code Playgroud)

请注意:clang++ 更详细地解释了这一点

bitfields.cpp:30:9: warning: width of bit-field 'a' (40 bits) exceeds the width of its type; value will be truncated to 32 bits [-Wbitfield-width]
    int a : 40;
    ^
Run Code Online (Sandbox Code Playgroud)

然而,似乎在幕后,编译器分配了另一个int值得的内存。或者至少,它决定了正确的尺寸。我猜编译器警告我们不要访问这个内存int a = bc_6::a(我敢打赌,int a那只会有字段的前 32 位bc_6::a......)。这可以通过bc_7其总大小为两个ints来确认,但第一个字段涵盖了其中的大部分。

最后替换intlong在上面的行为的例子如预期:

CHAR_BIT = 8 => sizeof(long) = 8
1,  1:  8
31, 1:  8
32, 1:  8
31, 2:  8
32, 32: 8
40, 32: 16
63, 1:  8
Run Code Online (Sandbox Code Playgroud)


unw*_*ind 9

是的,这是位域的语法.它们通常用于定义映射到硬件寄存器的结构.如果你决定使用它们,有一些事情要记住,一个是你不知道编译器如何进行布局,组成字段的实际字节中的排序和填充可以并且将在编译器之间有所不同(也许使用相同的编译器,但也有不同的优化设置).


Nil*_*nck 6

这是一个位域定义.

Name是一个能够存储40位信息的整数.颜色可以存储24位.

这通常是为了在经常需要的结构中节省一些空间,或者将代码压缩到易于为CPU处理的大小(在您的情况下是64位.完全适合64位机器上的CPU寄存器).

访问位域的代码虽然会慢一点.