在下面的例子中:
int main(int argc, char *argv[])
{
int16_t array1[] = {0xffff,0xffff,0xffff,0xffff};
char array2[] = {0xff,0xff,0xff,0xff};
printf("Char size: %d \nint16_t size: %d \n", sizeof(char), sizeof(int16_t));
if (*array1 == *array2)
printf("They are the same \n");
if (array1[0] == array2[0])
printf("They are the same \n");
printf("%x \n", array1[0]);
printf("%x \n", *array1);
printf("%x \n", array2[0]);
printf("%x \n", *array2);
}
输出:
Char size: 1
int16_t size: 2
They are the same
They are the same
ffffffff
ffffffff
ffffffff
ffffffff
为什么为char
和int16_t
打印32位值,为什么可以对它们进行比较并认为是相同的?
答案 0 :(得分:5)
它们是相同的,因为它们是-1的所有不同表示。
他们打印为32位'价值ff
,因为您使用的是32位计算机并且使用了%d
并且发生了默认参数促销(基本上,所有较小的内容都会被提升为{ {1}})。尝试使用int
。 (那可能会让你%hx
;除了使用ffff
或屏蔽ff
之外,我不知道如何获得unsigned char
。 }:& 0xff
。)
扩展"它们是相同的,因为它们是-1和#34;的所有不同表示形式:
printf("%x \n", array2[0] & 0xff)
是带符号的16位类型。它可以包含-32768到+32767范围内的值
int16_t
是8位类型,并且在您的计算机上它也显然已签名。因此它可以包含-128到+127范围内的值。
0xff是十进制255,这是一个无法在有符号字符中表示的值。如果将0xff分配给有符号的char,则该位模式最终会被解释为255,而不是-1。 (同样,如果你指定了0xfe,那么它将被解释为254,而不是-2。)
0xffff是十进制65535,这个值不能在char
中表示。如果将0xffff分配给int16_t
,则该位模式最终会被解释为65535,而不是-1。 (同样,如果你指定了0xfffe,那将被解释为65534,而不是-2。)
所以当你说
时int16_t
基本就好像你说的那样
int16_t array1[] = {0xffff,0xffff,0xffff,0xffff};
当你说
时int16_t array1[] = {-1,-1,-1,-1};
就好像你说的那样
char array2[] = {0xff,0xff,0xff,0xff};
这就是char array2[] = {-1,-1,-1,-1};
和*array1 == *array2
。
此外,值得注意的是,由于array1[0] == array2[0]
和array1
的类型,所有这些都非常重要。如果你改为说
array2
您会看到打印的不同值(uint16_t array3[] = {0xffff,0xffff,0xffff,0xffff};
unsigned char array4[] = {0xff,0xff,0xff,0xff};
和ffff
),ff
和array3
的值不会相同。
另一个答案说明" C在运行时没有类型信息"。在这种情况下,这是真的但有误导性。当编译器生成代码来处理来自array4
,array1
,array2
和array3
的值时,它生成的代码(当然 )在运行时有意义!)将基于他们的类型。特别是,在生成代码以从array4
和array1
(但不 array2
和array3
)中获取值时,编译器将使用指令在分配给较大类型的对象(例如32位)时执行符号扩展。这就是0xff和0xffff如何变成0xffffffff。
答案 1 :(得分:1)
由于C 在运行时中没有类型信息,并且使用普通%x
进行打印,因此告诉printf
您的指针指向{{1} }。糟糕的库函数只信任您...请参阅printf(3)
中的长度修饰符,了解如何为unsigned int
提供所需的信息。
答案 2 :(得分:1)
使用%x
打印负值会导致undefined behaviour,因此您不应该假设您所看到的内容有任何明智之处。
char
的正确格式说明符为%hhd
,int16_t
的格式说明符为"%" PRId16
。您需要#include <inttypes.h>
才能获得后一个宏。
由于默认参数促销,将%d
与char
和int16_t
1 一起使用也是正确的。如果您将代码更改为使用%d
而不是%x
,则它将不再显示未定义的行为,并且结果将有意义。
1 C标准实际上并没有这么说,但是假设这是作者的意图。