也许高三个字节变成0xFFFFFF的原因需要更多解释?
由于符号扩展,为 *s 打印的值的高三个字节的值为 0xFF。
The char
传递给 printf 的值被扩展为int
在致电之前printf
.
这是由于 C 的默认行为造成的。
在缺少...之下signed
or unsigned
,编译器可以默认解释char
as signed char
or unsigned char
。除非使用命令行选项或编译指示显式更改,否则它始终是其中之一。在这种情况下我们可以看到它是signed char
.
在缺乏更多信息(原型或强制转换)的情况下,C 通过:
-
int
, so char
, short
, unsigned char
unsigned short
被转换为int
。它从不传递 char、unsigned char、signed char,作为单个字节,它总是传递int
.
-
unsigned int
大小与int
所以该值不加改变地传递
编译器需要决定如何将较小的值转换为int
.
-
signed
值:的高字节int
是从较小值扩展的符号,这有效地向上复制顶部符号位以填充int
。如果较小的有符号值的最高位为 0,则高位字节填充为 0。如果较小的有符号值的最高位为 1,则高位字节填充为 1。因此 printf("%x ",*s ) 打印 ffffffc2
-
unsigned
值没有符号扩展,int 的高字节是“零填充”
因此,C 可以调用没有原型的函数(尽管编译器通常会对此发出警告)
所以你可以编写并期望它运行(尽管我希望你的编译器发出警告):
/* Notice the include is 'removed' so the C compiler does default behaviour */
/* #include <stdio.h> */
int main (int argc, const char * argv[]) {
signed char schar[] = "\x70\x80";
unsigned char uchar[] = "\x70\x80";
printf("schar[0]=%x schar[1]=%x uchar[0]=%x uchar[1]=%x\n",
schar[0], schar[1], uchar[0], uchar[1]);
return 0;
}
打印:
schar[0]=70 schar[1]=ffffff80 uchar[0]=70 uchar[1]=80
The char
我的(Mac 的 gcc)编译器将值解释为signed char
,因此编译器生成代码来签名扩展char
to the int
beforeprintf 调用。
如果有符号字符值设置了最高(符号)位 (\x80),则转换为int
标志延伸了char
价值。符号扩展填充高字节(在本例中,另外 3 个字节构成 4 字节)int
) 与 1,由 printf 打印为 ffffff80
当有符号字符值的顶部(符号)位被清除(\x70)时,转换为int
仍然标志延伸char
价值。在本例中,符号为 0,因此符号扩展用 0 填充高位字节,printf 将其打印为 70
我的示例显示了该值的情况unsigned char
。在这两种情况下,该值未进行符号扩展,因为该值是unsigned
。相反,它们被扩展为带有 0 填充的 int。 printf 可能看起来只打印一个字节,因为该值的相邻三个字节将为 0。但它正在打印整个int
,恰好该值为 0x00000070 和 0x00000080,因为unsigned char
值被转换为int
没有符号扩展。
您可以通过使用合适的格式 (%hhx) 强制 printf 仅打印 int 的低字节,因此这会正确打印原始 char 中的值:
/* Notice the include is 'removed' so the C compiler does default behaviour */
/* #include <stdio.h> */
int main (int argc, const char * argv[]) {
char schar[] = "\x70\x80";
unsigned char uchar[] = "\x70\x80";
printf("schar[0]=%hhx schar[1]=%hhx uchar[0]=%hhx uchar[1]=%hhx\n",
schar[0], schar[1], uchar[0], uchar[1]);
return 0;
}
这打印:
schar[0]=70 schar[1]=80 uchar[0]=70 uchar[1]=80
因为 printf 将 %hhx 解释为将 int 视为unsigned char
。这不会改变在调用 printf 之前 char 已符号扩展为 int 的事实。它只是告诉 printf 如何解释 int 内容的一种方法。
在某种程度上,对于signed char *schar
, 的含义%hhx
看起来有点误导,但 '%x' 格式解释int
as unsigned
无论如何,并且(使用我的 printf)没有格式可以打印带符号值的十六进制(恕我直言,这会令人困惑)。
遗憾的是,ISO/ANSI/... 并没有自由发布我们的编程语言标准,因此我无法指出该规范,但在网络上搜索可能会找到工作草案。我没有尝试去寻找他们。我推荐 Samuel P. Harbison 和 Guy L. Steele 编写的《C: A Reference Manual》作为 ISO 文档的更便宜的替代品。
HTH