[英]Why casting unsigned to signed directly in C gives correct result? [duplicate]
在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;
}
预期输出为:
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
但是,实际上,它输出
5
5
5
5
为什么?
您声称...
在C中,有符号整数和无符号整数在内存中的存储方式不同
...在很大程度上是错误的。 该标准改为指定 :
对于有符号整数类型,对象表示的位应分为三组:值位,填充位和符号位。 不需要任何填充位; 带符号的字符不得有任何填充位。 应该有一个符号位。 作为值位的每个位应具有与相应无符号类型的对象表示形式中的相同位相同的值 (如果有符号类型中有M个值位, 无符号类型中有N个值位,则M <= N)。 如果符号位为零,则它将不影响结果值。
(C2011 6.2.6.2/2;已添加重点)
因此,尽管有符号整数类型及其相应的无符号整数类型(具有相同的大小)的表示必须至少在以下方面有所不同:前者具有符号位而后者没有符号位,但实际上这些表示中的大多数位都准确对应。 该标准要求它。 小(ish)非负整数将在相应的有符号和无符号整数类型中相同地表示。
另外,一些评论提出了“严格别名规则”的问题,这是标准的6.5 / 7段 。 就像您的代码一样,它禁止通过不同类型的左值访问一种类型的对象,但是它允许一些显着的异常。 例外之一是您可以通过类型为
- 类型是与对象的有效类型相对应的有符号或无符号类型,
实际上,这就是您的代码所执行的操作,因此那里没有严格混叠违规。
与注释部分中的解释相反,我仍然想尝试证明您的整数全部以相同的方式存储在内存中。 我很高兴修改我的答案,但是目前我仍然不相信unsigned / signed int在内存中的存储方式有所不同[实际上,我知道它^^]。
测试程序:
#include <iostream>
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);
std::terminate();
return 0;
}
使用以下命令编译它:g ++ -O0 -g test.cpp
在GDB中运行它:gdb ./a.out
调用std :: terminate之后,我们可以检查原始内存:
(gdb) print/t main::a
$9 = 101
(gdb) print/t main::b
$10 = 101
(gdb) print/t main::c
$11 = 101
(gdb) print/t main::d
$12 = 101
(gdb)
整数都以相同的方式存储,即无符号或有符号整数。 唯一的区别是,一旦SIGNED_INT_MAX上的无符号int转换为有符号int,它们的解释方式就会不同。 但是,这种强制转换也不会完全改变内存。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.