如果我说错了什么,请纠正我。
您的问题有一个带有“未定义行为”的标志。我认为这是不对的。
如果你对这个程序有任何疑问,我建议你看看这个程序的反汇编代码。你所有的困惑都可以很容易地通过检查来解决。
输出:
-2 254
-2 254
这是正确的,也是中央行为。这种行为是由C语言本身或C语言标准决定的。
输出的关键取决于程序员希望如何解释FE
的存储值。如果您将FF
视为无符号字符,则它是255
(或FFFF
作为无符号短字符,它是65535
或FFFFFFFF
4294967295FF视为有符号字符(或FFFF
作为有符号短it s-1
或FFFFFFFF
-1),it s-1
。
正如您将FE
视为无符号字符一样,它是254
。请将<code>FE</code>作为一个有符号的字符,它是<code>-2
当您要求计算机存储-2
和254
时,计算机不识别正数或负数,它只识别0
(在电路中,它可能被称为“断开连接”或“断开”)和1
,它将在内存中的某个位置存储FE
(因为变量c
和变量d
是char类型,所以它占用1
字节)(正如@David c.Rankin所指出的,在用两个互补码编码负符号值的计算机上。
请参阅以下代码:
#include <stdio.h>
int main()
{
signed char c;
unsigned char d;
c = (signed char) 0xFE;
d = (unsigned char) c;
printf("%d %d
", c, d);
d = (unsigned char)0xFE;
c = (signed char) d;
printf("%d %d
", c, d);
return 0;
}
使用以下命令运行它:
clang -Wall -Wextra -pedantic -std=c89 foo.c && ./a.out
将输出:
-2 254
-2 254
为什么输出双-2 254
?
代码中没有-2
和254
。-2
和254
来自哪里?
简单解释:
我们发现变量c
和可变d
是char类型,但%d
输出int(或带符号int),编译器现在应该如何进行?答案是有符号扩展和无符号扩展。
因此,现在存储在变量c
中的值0xFE
已通过符号扩展转换为0xFFFFFFFE
,存储在变量d
的值0xFE
已通过零扩展转换为0x000000FE
0xFFFFFFFE打印为-2
且%d
时,且0x000000FE
254并%d
。(您是否不太熟悉或不太理解0xFFFFFFFE?下面有解释,让我们继续阅读。)
或者代码如下:
#include <stdio.h>
int main()
{
signed char c;
unsigned char d;
c = (signed char) 254;
d = (unsigned char) c;
printf("%d %d
", c, d);
d = (unsigned char)254;
c = (signed char) d;
printf("%d %d
", c, d);
return 0;
}
使用以下命令运行它:
clang -Wall -Wextra -pedantic -std=c89 foo.c && ./a.out
将输出:
-2 254
-2 254
为了更好地解释您的困惑,请查看以下代码。
#include <stdio.h>
int main()
{
signed char c;
unsigned char d;
c = (signed char) -2;
d = (unsigned char) c;
printf("%d %d %u %u
", c, d, c, d);
d = (unsigned char) 254;
c = (signed char) d;
printf("%d %d %u %u
", c, d, c, d);
return 0;
}
使用以下命令运行它:
clang -Wall -Wextra -pedantic -std=c89 foo.c && ./a.out
将输出:
-2 254 4294967294 254
-2 254 4294967294 254
或者使用以下命令运行它:
gcc -g -o foo foo.c && ./foo
将输出:
-2 254 4294967294 254
-2 254 4294967294 254
输出是正确的。
更多详细说明:
我们发现c或d是char类型,但%u
是输出unsignedint,编译器现在应该如何进行?答案是有符号扩展和无符号扩展。
当我们检查反汇编代码时,我们确实发现了符号扩展和零扩展。见下图:
我们发现,当为变量c
和变数d
赋值时使用字符类型(BYTE),但在之前打印可变c
可变d的值时,有一些指令,如movzx esi、BYTE PTR[rbp-0x1]
、movsx ecx、BYTE PTR[rbp-0x2]
vsx-eax,字节PTR[rbp-0x2],movzx
是零扩展,movsx
esi,ecx
、edx
eax=int
(ecx
占用4字节,int
的类型也占用4字节)。
因此,现在存储在变量c
中的值0xFE
已通过符号扩展转换为0xFFFFFFFE
,存储在变量d
的值0xFE
已通过零扩展转换为0x000000FE
0xFFFFFFFE为4294967294
且%u
时,打印的0xFFFFFE
是-2
而%d
,打印的0x000000FE
254
并%u
、打印的0x000000FE
则是254
%d
。
4294967294的表示见下图。
-2的表示见下图。
现在您可以看到,当输出c或d的值时,使用%d和%u将它们打印出来会产生不同的结果。但是,这两种表示都引用了存储在内存中的相同值关键是如何选择解释c或d的值。