为什么将无符号转换为直接用C签名会得到正确的结果?

dog*_*719 -1 c c++ unsigned-integer

在C中,有符号整数和无符号整数在内存中的存储方式不同.当类型在运行时清除时,C还隐式转换有符号整数和无符号整数.但是,当我尝试以下代码段时,

#include <stdio.h>

int main() {    
    unsigned int a = 5;
    signed int b = a;
    signed int c = *(unsigned int*)&a;
    signed int d = *(signed int*)&a;

    printf("%u\n", a);
    printf("%i\n", b);
    printf("%i\n", c);
    printf("%i\n", d);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

预期产量:

5
5                   //Implicit conversion occurs
5                   //Implicit conversion occurs, because it knows that *(unsigned int*)&a is an unsigned int
[some crazy number] //a is casted directly to signed int without conversion
Run Code Online (Sandbox Code Playgroud)

然而,实际上,它输出

5
5
5
5
Run Code Online (Sandbox Code Playgroud)

为什么?

Joh*_*ger 6

你声称......

在C中,有符号整数和无符号整数在内存中的存储方式不同

......很大程度上是错误的 该标准改为指定:

对于有符号整数类型,对象表示的位应分为三组:值位,填充位和符号位.不需要任何填充位; signed char不应有任何填充位.应该只有一个符号位.作为值位的每个位应具有与相应无符号类型的对象表示中的相同位相同的值(如果在有符号类型中有M个值位且在无符号类型中有N,则M <= N).如果符号位为零,则不应影响结果值.

(C2011 6.2.6.2/2;强调增加)

因此,尽管有符号整数类型的表示及其对应的无符号整数类型(具有相同大小)必须至少在前者具有符号位而后者不具有不同的情况下,所以表示的大多数位实际上完全对应.该标准要求它.小(ish),非负整数将在相应的有符号和无符号整数类型中相同地表示.

此外,一些评论提出了"严格别名规则"的问题,即标准的第6.5/7段.它禁止通过不同类型的左值访问一种类型的对象,就像你的代码一样,但它允许一些值得注意的例外.其中一个例外是您可以通过类型为的左值来访问对象

  • 与对象的有效类型对应的有符号或无符号类型的类型,

这实际上是你的代码所做的,所以那里没有严格别名违规.