Jay*_*hoi 251 c signed numeric-conversion numeric-limits
我有一个简单的程序:
#include <stdio.h>
#define INT32_MIN (-0x80000000)
int main(void)
{
long long bal = 0;
if(bal < INT32_MIN )
{
printf("Failed!!!");
}
else
{
printf("Success!!!");
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
条件if(bal < INT32_MIN )总是如此.这怎么可能?
如果我将宏更改为:
#define INT32_MIN (-2147483648L)
Run Code Online (Sandbox Code Playgroud)
有谁可以指出这个问题?
Lun*_*din 361
这非常微妙.
程序中的每个整数文字都有一个类型.它具有哪种类型由6.4.4.1中的表格规定:
Suffix Decimal Constant Octal or Hexadecimal Constant
none int int
long int unsigned int
long long int long int
unsigned long int
long long int
unsigned long long int
Run Code Online (Sandbox Code Playgroud)
如果文字编号不能适合默认int类型,它将尝试下一个更大的类型,如上表所示.因此对于常规十进制整数文字,它就像:
intlonglong long.Hex文字表现不同!如果文字不能适合签名类型int,它将首先尝试unsigned int继续尝试更大的类型.请参阅上表中的差异.
所以在32位系统上,你的文字0x80000000是类型的unsigned int.
这意味着您可以-在文字上应用一元运算符而不调用实现定义的行为,就像溢出有符号整数时一样.相反,你将获得价值0x80000000,一个正值.
bal < INT32_MIN调用通常的算术转换,表达式的结果0x80000000从中unsigned int提升long long.该值0x80000000保留,0小于0x80000000,因此结果.
当您2147483648L使用十进制表示法替换文字时,编译器不会选择unsigned int,而是尝试将其放入a中long.此外,L后缀表示long 如果可能,您需要一个.如果你继续阅读6.4.4.1中提到的表,L后缀实际上有类似的规则:如果数字不适合所请求的内容long,而不是32位的话,编译器会给你一个long long它的位置很合适.
Bat*_*eba 27
0x80000000是一个unsigned值为2147483648 的文字.
对此使用一元减号仍会为您提供一个非零值的无符号类型.(事实上,对于非零值x,您最终得到的值是UINT_MAX - x + 1.)
Vla*_*cow 23
这个整数文字0x80000000有类型unsigned int.
根据C标准(6.4.4.1整数常数)
5整数常量的类型是相应列表中可以表示其值的第一个.
并且这个整数常量可以用类型表示unsigned int.
所以这个表达
-0x80000000具有相同的unsigned int类型.此外,它0x80000000在二进制补码表示中具有相同的值
,计算以下方式
-0x80000000 = ~0x80000000 + 1 => 0x7FFFFFFF + 1 => 0x80000000
Run Code Online (Sandbox Code Playgroud)
如果要编写,这会产生副作用
int x = INT_MIN;
x = abs( x );
Run Code Online (Sandbox Code Playgroud)
结果将再次出现INT_MIN.
因此在这种情况下
bal < INT32_MIN
Run Code Online (Sandbox Code Playgroud)
有比较0用无符号的值0x80000000转换长长整型根据通常的算术转换的规则输入.
很明显,0小于0x80000000.
dbu*_*ush 12
数字常量0x80000000是类型unsigned int.如果我们采取-0x80000000并做2s恭维数学,我们得到这个:
~0x80000000 = 0x7FFFFFFF
0x7FFFFFFF + 1 = 0x80000000
Run Code Online (Sandbox Code Playgroud)
所以-0x80000000 == 0x80000000.并且比较(0 < 0x80000000)(因为0x80000000是无符号的)是真的.
chu*_*ica 11
在思考-数字常量的一部分时会出现混淆.
在下面的代码0x80000000是数字常量.它的类型仅在此确定.将-被应用之后并不会改变类型.
#define INT32_MIN (-0x80000000)
long long bal = 0;
if (bal < INT32_MIN )
Run Code Online (Sandbox Code Playgroud)
原始的未经修饰的数字常数是正面的.
如果是小数,然后被分配类型是将其持有第一类:int,long,long long.
如果常数是八进制或十六进制,它会保持它的第一种类型:int,unsigned,long,unsigned long,long long,unsigned long long.
0x80000000,在OP的系统上得到unsigned或的类型unsigned long.无论哪种方式,它都是一些无符号类型.
-0x80000000也是一些非零值并且是一些无符号类型,它大于0.当代码将其与a 进行比较时,比较的两侧long long的值不会改变,所以0 < INT32_MIN是真的.
另一种定义避免了这种奇怪的行为
#define INT32_MIN (-2147483647 - 1)
Run Code Online (Sandbox Code Playgroud)
让我们走在梦幻之地了一段时间,其中int和unsigned48位.
然后0x80000000适合,int所以类型int. -0x80000000然后是负数,打印输出的结果是不同的.
[回到真实的话]
由于0x80000000在签名类型之前适合某些无符号类型,因为它比some_signed_MAX内部大some_unsigned_MAX,所以它是一些无符号类型.
C有一个规则,即整数文字可能是signed或unsigned取决于它是否适合signed或unsigned(整数提升).在一32台机器上,文字0x80000000将是unsigned.2的补充-0x80000000是0x80000000 在32位机器上.因此,比较bal < INT32_MIN是在比较之间signed和unsigned之前,根据C规则unsigned int将转换为long long.
[...]否则,如果带有符号整数类型的操作数的类型可以表示具有无符号整数类型的操作数类型的所有值,则具有无符号整数类型的操作数将转换为操作数的类型.有符号整数类型.
因此,bal < INT32_MIN永远true.
| 归档时间: |
|
| 查看次数: |
15060 次 |
| 最近记录: |