iam*_*ind 95 c c++ bit-fields signed-integer implementation-defined-behavior
我在Quora帖子中看到了以下代码:
#include <stdio.h>
struct mystruct { int enabled:1; };
int main()
{
struct mystruct s;
s.enabled = 1;
if(s.enabled == 1)
printf("Is enabled\n"); // --> we think this to be printed
else
printf("Is disabled !!\n");
}
Run Code Online (Sandbox Code Playgroud)
在C&C++中,代码的输出都是意外的,
被禁用 !!
虽然在那篇文章中给出了"符号位"相关的解释,但是我无法理解,我们如何设置某些内容然后它没有反映出来.
有人可以给出更详细的解释吗?
Lun*_*din 76
标准对比特字段的定义非常差.鉴于此代码struct mystruct {int enabled:1;};,我们不知道:
int:n位域视为有符号或无符号.关于最后一部分,C17 6.7.2.1/10说:
位字段被解释为具有由指定位数组成的有符号或无符号整数类型125)
解释上述内容的非规范性说明:
125)如上面6.7.2中所规定的,如果使用的实际类型说明符是
int或者定义为typedef-nameint,则无论位字段是有符号还是无符号,它都是实现定义的.
如果要将位域视为signed int并且您制作了一些大小1,则没有数据空间,仅用于符号位.这就是为什么你的程序可能会在某些编译器上给出奇怪结果的原因.
好的做法:
int类型进行任何形式的位操作.Hos*_*ork 57
我无法理解,我们如何设置某些内容然后它不会显示出来.
你问为什么它编译而不是给你一个错误?
是的,它理想情况下应该给你一个错误.如果您使用编译器的警告,它确实如此.在GCC中,有-Werror -Wall -pedantic:
main.cpp: In function 'int main()':
main.cpp:7:15: error: overflow in conversion from 'int' to 'signed char:1'
changes value from '1' to '-1' [-Werror=overflow]
s.enabled = 1;
^
Run Code Online (Sandbox Code Playgroud)
为什么这是由于实现定义与错误相关的原因可能更多地与历史使用有关,其中需要强制转换意味着破坏旧代码.该标准的作者可能认为警告足以弥补相关人员的不足.
为了引入一些规定主义,我将回应@Lundin的声明:"永远不要将比特字段用于任何目的." 如果你有充分的理由让你的内存布局细节低级别具体,那么你首先会想到你需要的位域,你几乎可以肯定的其他相关要求将会遇到他们的不足之处.
(TL; DR - 如果你足够复杂,合法地"需要"位字段,那么它们的定义不够明确,无法为你服务.)
Nat*_*ica 22
这是实现定义的行为.我假设你运行它的机器使用twos-compliment signed整数并int在这种情况下将其视为有符号整数来解释为什么你不输入if语句的真正部分.
struct mystruct { int enabled:1; };
Run Code Online (Sandbox Code Playgroud)
声明enable为1位位字段.由于它已签名,因此有效值为-1和0.将字段设置为1溢出该位返回-1(这是未定义的行为)
基本上在处理有符号的位字段时,最大值2^(bits - 1) - 1就是0这种情况.
Pau*_*vie 10
你可以把它想象成2的补码系统,最左边的位是符号位.因此,设置最左位的任何有符号整数都是负值.
如果您有1位有符号整数,则它只有符号位.因此,分配1给该单个位只能设置符号位.因此,当读回它时,该值被解释为负数,因此为-1.
1位有符号整数可以容纳的值是-2^(n-1)= -2^(1-1)= -2^0= -1和2^n-1= 2^1-1=0
根据C++标准n4713,提供了非常相似的代码片段.使用的类型是BOOL(自定义),但它可以应用于任何类型.
12.2.4
4如果将值true或false存储到
bool任何大小的类型的位字段(包括一位位字段)中,则原始bool值和位字段的值应相等.如果枚举器的值存储在相同枚举类型的位字段中,并且位字段中的位数足以容纳该枚举类型的所有值(10.2),则原始枚举器值和比特字段的值应相等.[例如:Run Code Online (Sandbox Code Playgroud)enum BOOL { FALSE=0, TRUE=1 }; struct A { BOOL b:1; }; A a; void f() { a.b = TRUE; if (a.b == TRUE) // yields true { /* ... */ } }- 结束例子]
乍一看,大胆的部分似乎是开放的解释.但是,正确的意图在enum BOOL得到的时候变得清晰int.
enum BOOL : int { FALSE=0, TRUE=1 }; // ***this line
struct mystruct { BOOL enabled:1; };
int main()
{
struct mystruct s;
s.enabled = TRUE;
if(s.enabled == TRUE)
printf("Is enabled\n"); // --> we think this to be printed
else
printf("Is disabled !!\n");
}
Run Code Online (Sandbox Code Playgroud)
使用上面的代码,它会发出警告,但不-Wall -pedantic:
警告:'mystruct :: enabled'太小,无法容纳'enum BOOL'的所有值
struct mystruct { BOOL enabled:1; };
输出是:
被禁用 !!(使用时
enum BOOL : int)
如果enum BOOL : int变得简单enum BOOL,那么输出就像上面的标准pasage所指定的那样:
启用(使用时
enum BOOL)
因此,可以得出结论,即使其他答案很少,该int类型也不足以在单个比特位字段中存储值"1".
| 归档时间: |
|
| 查看次数: |
5152 次 |
| 最近记录: |