不鼓励使用int类型的位字段吗? C++标准(N33 37):

不鼓励使用int类型的位字段吗? C++标准(N33 37):,c++,bit-fields,C++,Bit Fields,9.6位字段 4如果值true或false存储在任何大小的bool类型的位字段中(包括一位位字段),则原始bool值和位字段的值应相等。如果枚举数的值存储在相同枚举类型的位字段中,且位字段中的位数足够大,足以容纳该枚举类型(7.2)的所有值,则原始枚举数值和位字段的值应相等 该标准对其他类型的位字段的任何此类行为都不作承诺。为了理解g++(4.7.3)如何处理其他类型的位字段,我使用了以下测试程序: #include <iostream> enum TestEnum { V1

9.6位字段

4如果值
true
false
存储在任何大小的
bool
类型的位字段中(包括一位位字段),则原始
bool
值和位字段的值应相等。如果枚举数的值存储在相同枚举类型的位字段中,且位字段中的位数足够大,足以容纳该枚举类型(7.2)的所有值,则原始枚举数值和位字段的值应相等

该标准对其他类型的位字段的任何此类行为都不作承诺。为了理解g++(4.7.3)如何处理其他类型的位字段,我使用了以下测试程序:

#include <iostream>

enum TestEnum
{
   V1 = 0,
   V2
};

struct Foo
{
   bool          d1:1;
   TestEnum      d2:1;
   int           d3:1;
   unsigned int  d4:1;
};

int main()
{
   Foo foo;
   foo.d1 = true;
   foo.d2 = V2;
   foo.d3 = 1;
   foo.d4 = 1;

   std::cout << std::boolalpha;

   std::cout << "d1: " << foo.d1 << std::endl;
   std::cout << "d2: " << foo.d2 << std::endl;
   std::cout << "d3: " << foo.d3 << std::endl;
   std::cout << "d4: " << foo.d4 << std::endl;
   std::cout << std::endl;

   std::cout << (foo.d1 == true) << std::endl;
   std::cout << (foo.d2 == V2) << std::endl;
   std::cout << (foo.d3 == 1) << std::endl;
   std::cout << (foo.d4 == 1) << std::endl;

   return 0;
}
#包括
测试枚举
{
V1=0,
V2
};
结构Foo
{
布尔d1:1;
睾丸d2:1;
int d3:1;
无符号整数d4:1;
};
int main()
{
富富,;
foo.d1=真;
foo.d2=V2;
foo.d3=1;
foo.d4=1;

STD:CUT<代码> INT/INGED>是代码>签名< /代码>,在C++中可以使用,所以在第一个代码> INT/INTCOR>字节符号可以被存储。当有2个比特用于<代码>签名INT/CUT>时,它可以等于1,

< P>这是完全合乎逻辑的。<代码> INT/COD>是一个带符号整数类型,如果底层架构使用两个补码表示有符号整数(正如所有现代体系结构所做的那样),那么高阶位就是符号位。因此,1位有符号整数位字段可以取值
0
-1
。例如,3位有符号整数位字段可以取值
-4
3
之间的值


没有理由全面禁止有符号整数位字段,只要您了解二的补码表示。

是的,类型为
int
的位字段是个坏主意,因为它们的符号是由实现定义的。请改用
有符号int
无符号int

对于非位字段声明,类型名
int
完全等同于
signed int
(或
int signed
,或
signed
)。对于
short
long
long
遵循相同的模式:未加修饰的类型名称是有符号版本,您必须添加
unsigned
关键字来命名相应的无符号类型

出于历史原因,位字段是一种特殊情况。使用
int
类型定义的位字段相当于使用
signed int
的同一声明,或使用
unsigned int
的同一声明。选择由实现定义(即,它由编译器决定,而不是由程序员决定)。位字段是唯一的上下文,
int
signed int
不(一定)同义。这同样适用于
char
short
long
long

引用C++11标准第9.6节[class.bit]:

它是实现定义的,无论是普通的还是显式的 有符号或无符号)
字符
整数
位字段无效 签名或未签名

(我不完全确定这一点的理由。非常旧的C版本没有
unsigned
关键字,而且无符号位字段通常比有符号位字段更有用。可能是一些早期的C编译器在引入
unsigned
关键字之前实现了位字段。默认情况下,使位字段无符号,即使声明为
int
,也可能只是为了方便起见。除了避免破坏旧代码之外,没有真正的理由遵守规则。)

大多数位字段都是无符号的,这当然意味着它们应该这样定义

如果您想要一个有符号位字段(例如,一个4位字段,可以表示非二元补码系统中从-8到+7的值,或者从-7到+7的值),那么您应该显式地将其定义为
有符号int
。如果您将其定义为
无符号int
,那么一些编译器会将其视为
无符号int


如果您不关心位字段是有符号的还是无符号的,那么您可以将其定义为
int
——但是如果您定义位字段,那么您几乎肯定会关心它是有符号的还是无符号的。

您完全可以使用任何大小不大于
无符号int
位字段有符号的位字段是合法的(至少在宽度大于1的情况下),我个人不喜欢使用它们。但是,如果您确实希望使用有符号位字段,则应显式将其标记为有符号的,因为它依赖于实现,取决于非限定的
int
位字段是有符号的还是无符号的。(这类似于
char
,但没有显式非限定
char*
文本的复杂特性。)

因此,在这种程度上,我同意不鼓励使用
int
位字段。[注1]虽然我不知道有哪种实现中,
int
位字段是隐式无符号的,但该标准肯定允许它,因此,如果您对符号没有明确的定义,则有很多机会出现特定于实现的意外行为

标准规定有符号整数表示由可选的填充位、恰好一个符号位和值位组成。虽然标准不保证至少有一个值位,--正如OP中的示例所示,
gcc
并不坚持有-我认为这是对s的合理解释标准,因为它明确允许 d1: true d2: 1 d3: -1 d4: 1 true true false true