C++ C+中的位字段+;

C++ C+中的位字段+;,c++,bit-fields,C++,Bit Fields,我有以下自学代码: #include <iostream> using namespace std; struct bitfields{ unsigned field1: 3; unsigned field2: 4; unsigned int k: 4; }; int main(){ bitfields field; field.field1=8; field.field2=1e7; field.k=18; cout

我有以下自学代码:

#include <iostream>
using namespace std;
struct bitfields{
    unsigned field1: 3;
    unsigned field2: 4;
    unsigned int k:  4;
};

int main(){
    bitfields field;
    field.field1=8;
    field.field2=1e7;
    field.k=18;
    cout<<field.k<<endl;
    cout<<field.field1<<endl;
    cout<<field.field2<<endl;
    return 0;
}

例如,
filed1
可以从0到7(包括),
field2
k
可以从0到15。为什么会有这样的结果?也许应该全部为零?

您的字段太多了。让我们以
k
为例,它的宽度为4位。它可以保存值,如您所说,从0到15,以二进制表示

0  -> 0000
1  -> 0001
2  -> 0010
3  -> 0011
...
14 -> 1110
15 -> 1111
所以当你赋值18时,用二进制表示

18 -> 1 0010 (space added between 4th and 5th bit for clarity)
k
只能保存较低的四位,因此

k = 0010 = 2.

对于您的其余字段,等效值也适用。

您得到这些结果,因为赋值溢出了每个位字段

变量
filed1
为3位,但8需要4位来表示(1000)。较低的三位均为零,因此
filed1
为零

对于
filed2
,17由10001表示,但
filed2
仅为四位。下四位表示值1

最后,对于
k
,18由10010表示,但
k
仅为四位。下四位表示值2

我希望这有助于澄清问题。在C++中,当你点击上限时,任何未签名的类型都会被包裹起来。当您定义一个4位的位字段时,您存储的每个值也会被包装起来。大小为4的位字段的可能值为0-15。如果存储'17',则换行到'1',对于'18',则再转到'2'

从数学上讲,包装值是原始值,与目标类型的可能值的数量成模:

对于大小为4的位字段(2**4个可能值):

对于大小为3的位字段(2**3个可能值):


[1] 这对于有符号类型是不正确的,因为它是未定义的,然后会发生什么情况。

为什么对有符号类型是未定义的?INTK:4将保持-8到7,分配18仍将产生2,而分配15将产生-1。我假设二的补码运算,这毕竟是最常见的。任何其他算法都将被很好地定义,尽管不一样。C++开发中的一个目标是尽可能不了解底层机器的特性。因此,标准文档没有对有符号整数的表示或它们的行为做出任何假设:它们可以是1-补码,并且可能会陷入溢出。当然,了解这一点很重要。例如,仍然有人编写溢出检查,如
x+1
k = 0010 = 2.
18 % 16 == 2
17 % 16 == 1
8 % 8 == 0.