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

C 转换为uint64时int32或32位指针的意外符号扩展,c,types,casting,type-conversion,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( " pro

我使用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:00000000 FFFFFFFF b:FFFFFFFFFFFFFF

我认为
intorig=(int)0xFFFFFFFF
争议较小,因为我没有将指针分配给整数。然而,结果是一样的

有人能向我解释一下C标准中的什么地方涵盖了
orig
是从0xFFFFFFFF扩展到0xffffffffff的符号吗

我假设
(unsigned\uu int64)orig
将变成0x00000000FFFFFFFF。似乎转换首先是有符号的_int64类型,然后变成无符号的?

编辑:这个问题的答案是指针是符号扩展的,这就是为什么我在gcc和msvc中看到这种行为。然而,我不明白为什么当我做类似于
(unsigned uu int64)(int)0xf000000
的事情时,它的符号扩展到0xfffffff000000,但是
(unsigned uu int64)0xf000000
并没有显示我想要的东西,即0x00000000f000000

编辑:以上编辑的答案。
(unsigned\uu int64)(int)0xF0000000
被符号扩展的原因是,正如用户所指出的:

将有符号类型(或任何类型)转换为无符号类型 始终通过模1加上 目标类型

(unsigned\uu int64)中,0xF0000000
0xF0000000以无符号整数类型开始,因为它不能放入整数类型。接下来,将转换已无符号的类型
无符号\uu int64

因此,对于我来说,这个函数的作用是将32位或64位指针返回为
无符号\uu int64
要进行比较,我必须首先将32位应用程序中的32位指针转换为无符号类型,然后再升级为
无符号\uu int64
。生成的代码如下所示(但是,您知道,更好):



再次编辑: 以下是我在C99标准中发现的内容: 6.3.1.3有符号和无符号整数

  • 1当整数类型的值转换为另一个整数时 如果值可以由新的 类型,它是不变的
  • 2否则,如果新类型是无符号的,则该值由 重复地在最大值上加上或减去一个 可以在新类型中表示,直到值位于 新类型的范围。49)
  • 3否则,将对新类型进行签名,并且无法删除该值 在其中有代表性;结果要么是定义了实现,要么是 引发实现定义的信号
  • 49)规则描述的是基于数学值的算术,而不是 给定类型表达式的值
  • 来自C99标准(§6.3.2.3/6)的:

    任何指针类型都可以转换为整数类型。除前面指定的情况外, 结果是定义了实现。如果结果不能用整数类型表示, 该行为未定义。结果不必在任何整数的值范围内 类型


    因此,您需要找到有关这方面的编译器文档。

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

    是gcc如何实现的,即,如果整数类型大于指针类型,则符号扩展(无论整数是有符号的还是无符号的,都会发生这种情况,因为gcc就是这样决定实现它的)

    据推测,msvc的行为类似。编辑,我能在MSDN上找到的最接近的东西是/,这表明将32位指针转换为64位也会扩展符号。

    整数常量(例如,
    0x00000000ffffff
    )默认为有符号整数,因此在分配给64位变量时可能会经历符号扩展。尝试将第3行中的值替换为:

    0x00000000FFFFFFFFULL
    

    使用此选项可避免标志扩展:

    unsigned __int64 a = 0x00000000FFFFFFFFLL;
    

    注意末尾的L。如果没有此选项,它将被解释为32位带符号的数字(-1),然后进行强制转换。

    您的指针是64位的吗?没有32位指针。这是对我正在处理的一个函数以及其他我确实无法改变的事情的过度简化,以证明我遇到的问题。在转换为无符号INT64之前,您的32位指针已转换为32位int。另请参见:“…如果指针表示形式大于整数类型,[然后是GCC]符号扩展指针…GCC的未来版本可能会进行零扩展,或使用目标定义的ptr_扩展模式。不要依赖符号扩展”。您不需要使用U,因为它将正确解释为两个Ls
    0xFFFFFF
    不是有符号整数。它是一个无符号整数。R:除非该值被指定为无符号(带有
    U
    前缀),否则默认情况下它是有符号的。即使它不能适应有符号整数@达斯乌夫:不是真的。根据6.4.4.1整型常量,“整型常量的类型是可以表示其值的对应列表中的第一个。”对于“无后缀”十六进制常量,列表是“int,unsigned int,long,unsigned long,long long,unsigned long long long”。为什么在没有注释的情况下被否决。这个网站上有一些真正的混蛋,他们在没有任何理由或解释的情况下投了反对票。按照C标准,将0xffffffff解释为-1是非法的。如果MSVC在这方面不符合规定,我不会感到惊讶。仅供参考,我不是反对者,但答案是错误的。如果没有LL后缀,则类型为
    unsigned int
    。此答案是正确的。这些链接很有用。让我问你,暂时撇开指针不谈,为什么像
    ((unsigned uu int64)(int)0xFFFFFFFF)
    在gcc和msvc中的值是0xffffffffff?@test:有符号类型(或任何类型)到无符号类型的转换总是通过模1加上目标t的最大值来实现的
    unsigned __int64 a = 0x00000000FFFFFFFFLL;