我使用Visual Studio 2010(cl.exe /W4
)将此代码编译为C文件:
int main( int argc, char *argv[] )
{
unsigned __int64 a = 0x00000000FFFFFFFF;
void *orig = (void *)0xFFFFFFFF;
unsigned __int64 b = (unsigned __int64)orig;
if( a != b )
printf( " problem\ta: %016I64X\tb: %016I64X\n", a, b );
return;
}
没有警告,结果是:
问题a:00000000FFFFFFFF b:FFFFFFFFFFFFFFFF
我认为int orig = (int)0xFFFFFFFF
不会引起争议,因为我没有指定一个整数的指针。但结果是一样的。
有人可以向我解释在C标准中,orig
是从0xFFFFFFFF扩展到0xFFFFFFFFFFFFFFFF的标志吗?
我原以为(unsigned __int64)orig
会变成0x00000000FFFFFFFF。似乎转换首先是签名的__int64类型,然后它变为无符号?
编辑:这个问题已被回答,指针是符号扩展的,这就是我在gcc和msvc中看到这种行为的原因。但是我不明白为什么当我做(unsigned __int64)(int)0xF0000000
这样的事情时,它的符号扩展到0xFFFFFFFFF0000000,但(unsigned __int64)0xF0000000
没有显示我想要的东西,即0x00000000F0000000。
编辑:上述编辑的答案。 (unsigned __int64)(int)0xF0000000
符号扩展的原因是,正如用户R所指出的那样:
将签名类型(或任何类型)转换为无符号类型 始终通过减少模数加上最大值来实现 目的地类型。
在(unsigned __int64)0xF0000000
中,0xF0000000以无符号整数类型开始,因为它不适合整数类型。接下来,已经无符号的类型将被转换为unsigned __int64
。
因此,对我来说这是一个函数,它返回一个32位或64位指针作为unsigned __int64
进行比较我必须首先将32位应用程序中的32位指针转换为在宣传到unsigned __int64
之前的无符号类型。结果代码看起来像这样(但是,你知道,更好):
unsigned __int64 functionidontcontrol( char * );
unsigned __int64 x;
void *y = thisisa32bitaddress;
x = functionidontcontrol(str);
if( x != (uintptr_t)y )
再次编辑:
这是我在C99标准中找到的:
6.3.1.3有符号和无符号整数
答案 0 :(得分:6)
将指针转换为/从整数转换为实现定义。
Here是gcc如何做到的,即如果整数类型大于指针类型,则符号会扩展(无论整数是有符号还是无符号,都会发生这种情况,因为这就是gcc决定实现的方式它)。
据推测,msvc表现相似。编辑,我在MSDN上找到的最接近的东西是this / this,这表明将32位指针转换为64位也会对符号进行扩展。
答案 1 :(得分:0)
根据C99标准(§6.3.2.3/ 6):
任何指针类型都可以转换为整数类型。除了之前指定的, 结果是实现定义的。如果结果无法以整数类型表示, 行为未定义。结果不必在任何整数的值范围内 类型。
所以你需要找到你的编译器文档来讨论它。
答案 2 :(得分:0)
默认情况下,整数常量(例如0x00000000FFFFFFFF
)是有符号整数,因此在分配给64位变量时可能会出现符号扩展。尝试用第3行替换第3行的值:
0x00000000FFFFFFFFULL
答案 3 :(得分:0)
使用它来避免符号扩展名:
unsigned __int64 a = 0x00000000FFFFFFFFLL;
注意L的结尾。如果没有它,它将被解释为32位有符号数(-1),然后进行转换。