任何人都可以提供一些代码示例,这些代码示例在使用fwrapv vs。编译时会有不同的行为。
它表示-fwrapv应该“假设加法,减法和乘法的带符号算术溢出,使用二进制补码表示包装。”
但每当我尝试溢出时,结果与fwrapv相同或不同。
答案 0 :(得分:8)
想想这个功能:
int f(int i) {
return i+1 > i;
}
从数学上讲,对于任何整数i+1
,i
应始终大于i
。但是,对于32位int
,有一个i
值使该语句为false,即2147483647
(即0x7FFFFFFF
,即INT_MAX
)。在该号码中添加一个将导致溢出,根据2的赞美表示,新值将环绕并变为-2147483648
。因此,i+1>1
变为-2147483648>2147483647
,这是假的。
当您编译而没有-fwrapv
时,编译器将假定溢出是“非包装”。它将优化该函数以始终返回1
(忽略溢出情况)。
当您使用-fwrapv
编译时,该功能不会被优化,并且它将具有添加1并比较这两个值的逻辑,因为现在,溢出就是包裹着#39; (即,溢出的数字将根据2的恭维表示进行换行。)
答案 1 :(得分:4)
for (int i=0; i>=0; i++)
printf("%d\n", i);
使用-fwrapv
,循环将在INT_MAX
次迭代后终止。没有,它可以做任何事情,因为当i++
具有值i
时,通过评估INT_MAX
无条件地调用未定义的行为。实际上,优化编译器可能会省略循环条件并产生无限循环。
答案 2 :(得分:1)
在使用新版本的 gcc 编译器时,我偶然发现了一个问题,该问题使标志 -fwrapv 变得清晰。
char Data[8]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
int a=256*(256*(256*Data[3]+Data[2])+Data[1])+Data[0];
如果您使用 -fwrapv 标志,结果将为 -1。 但是你做到了吗:
if(a<0)
printf("the value of a %d is negative\n",a);
else
printf("the value of a %d is positive\n",a);
它将打印“a -1 的值是正数”,因为在优化时它会删除第一部分,因为正数的 + - 和 * 将始终为正数(char 是无符号的)。
当您使用 -fwrapv 标志编译时,它将打印正确答案。
如果你使用这个:
int a=(Data[3]<<24)+(Data[2]<<16)+(Data[1]<<8)+Data[0];
无论是否带有标志,代码都按预期工作。
答案 3 :(得分:0)
ISO标准工作组WG14的存在是为了建立一个所有C编译器必须遵守的约定。一些编译器可能(并且确实)也实现了扩展。根据ISO标准C,这些扩展被认为是以下之一:
C11/3.4.3 establishes a definition for undefined behaviour and gives an extremely familiar example,在使用不可移植或错误的程序构造时,远远优于我能写的任何东西:
1 未定义的行为行为或国际标准没有要求的错误数据
2注意可能的未定义行为包括完全忽略具有不可预测结果的情况,在翻译或程序执行期间以环境特征(有或没有发出诊断消息)的文档方式行事,终止翻译或执行(发出诊断信息)。
3示例未定义行为的示例是整数溢出的行为。
还有未指明的行为,但我会将其作为练习留给您阅读标准中的内容。
小心踏到的地方。这是少数普遍接受的未定义行为中的一种,其中通常预期在没有陷阱重复的二进制补码表示中将发生LIA样式包装。重要的是要意识到存在使用与包含所有1的位表示相对应的陷阱表示的实现。
总而言之,fwrapv
和ftrapv
存在是为了向您传递选择,开发人员必须选择以此为代表,并且选择是签名整数时会发生的情况发生溢出。当然,他们必须选择默认值,在您的情况下,默认值与fwrapv
而不是ftrapv
相关联。情况并非如此,并且不需要这些编译器选项更改任何的事情。