转换为uint64时,int32或32位指针的意外符号扩展

loo*_*oop 3 c types casting type-conversion

我使用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;
}
Run Code Online (Sandbox Code Playgroud)

没有警告,结果是:

问题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所述:

有符号类型(或任何类型)到无符号类型的转换 总是通过减少模1加上目标类型的最大值来进行.

并且在(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 )
Run Code Online (Sandbox Code Playgroud)



再次编辑:这是我在C99标准中找到的:6.3.1.3有符号和无符号整数

  • 1当具有整数类型的值转换为除_Bool之外的另一个整数类型时,如果该值可以由新类型表示,则它将保持不变.
  • 2否则,如果新类型是无符号的,则通过重复加或减一个可以在新类型中表示的最大值来转换该值,直到该值在新类型的范围内.49)
  • 3否则,新类型已签名且值无法在其中表示; 结果是实现定义的,或者引发实现定义的信号.
  • 49)规则描述了数学值的算术,而不是给定类型表达式的值.

nos*_*nos 6

将指针转换为/从整数转换是实现定义的.

下面是gcc如何做到这一点,即如果整数类型大于指针类型,则符号会扩展(无论整数是有符号还是无符号,都会发生这种情况,只是因为这是gcc决定实现它的方式).

据推测,msvc表现相似.编辑,我在MSDN上找到的最接近的东西就是这个/this,这表明将32位指针转换为64位也符号扩展.