Char 和 int16 数组元素都显示为 32 位十六进制?
Char and int16 array element both shown as 32bit hex?
在下面的例子中:
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 位值,为什么可以比较它们并认为它们相同?
它们是相同的,因为它们都是 -1 的不同表示。
它们打印为 32 位的 ff
因为你在 32 位机器上并且你使用了 %d
和 默认参数 promotions 发生了(基本上,所有较小的东西都被提升为 int
)。尝试使用 %hx
。 (这可能会让你得到 ffff
;除了使用 unsigned char
或使用 & 0xff
掩码之外,我不知道有什么方法可以在这里得到 ff
:printf("%x \n", array2[0] & 0xff)
.)
在 "They're the same because they're all different representations of -1" 上扩展:
int16_t
是有符号的 16 位类型。它可以包含 -32768 到 +32767 范围内的值。
char
是一个 8 位类型,在你的机器上它显然也被签名了。因此它可以包含 -128 到 +127 范围内的值。
0xff 是十进制的 255,一个不能用有符号字符表示的值。如果将 0xff 分配给带符号的字符,则该位模式最终不会被解释为 255,而是 -1。 (同样,如果您指定 0xfe,则不会将其解释为 254,而是 -2。)
0xffff 是十进制的 65535,这个值不能用 int16_t
表示。如果将 0xffff 分配给 int16_t
,该位模式最终不会被解释为 65535,而是 -1。 (同样,如果您分配 0xfffe,则不会将其解释为 65534,而是 -2。)
所以当你说
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
和 array4
的值不会相同。
另一个回答说 "there is no type information in C at runtime"。这是真的,但在这种情况下具有误导性。当编译器生成代码来操作 array1
、array2
、array3
和 array4
的值时,它生成的代码(当然 是 在运行时很重要!)将基于它们的类型。特别是,当生成代码以从 array1
和 array2
获取值时(但 而不是 array3
和 array4
),编译器将在分配给更大类型的对象(例如 32 位)时,使用执行 符号扩展 的指令。这就是 0xff 和 0xffff 变成 0xffffffff 的方式。
因为 C 在运行时 中没有类型信息,并且通过使用普通的 %x
进行打印,您告诉 printf
您的指针指向一个 unsigned int
。糟糕的库函数只是相信你...请参阅 printf(3)
中的 长度修饰符 以了解如何为 printf
提供所需的信息。
使用 %x
打印负值会导致 undefined behaviour,因此您不应假设您所看到的内容是合理的。
char
的正确格式说明符是 %hhd
,int16_t
的正确格式说明符是 "%" PRId16
。您将需要 #include <inttypes.h>
来获取后一个宏。
由于默认参数促销,将%d
与char
和int16_t
一起使用也是正确的1。如果您将代码更改为使用 %d
而不是 %x
,它将不再表现出未定义的行为,并且结果将是有意义的。
1 C 标准实际上并没有这么说,但假定那是作者的意图。
在下面的例子中:
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 位值,为什么可以比较它们并认为它们相同?
它们是相同的,因为它们都是 -1 的不同表示。
它们打印为 32 位的 ff
因为你在 32 位机器上并且你使用了 %d
和 默认参数 promotions 发生了(基本上,所有较小的东西都被提升为 int
)。尝试使用 %hx
。 (这可能会让你得到 ffff
;除了使用 unsigned char
或使用 & 0xff
掩码之外,我不知道有什么方法可以在这里得到 ff
:printf("%x \n", array2[0] & 0xff)
.)
在 "They're the same because they're all different representations of -1" 上扩展:
int16_t
是有符号的 16 位类型。它可以包含 -32768 到 +32767 范围内的值。
char
是一个 8 位类型,在你的机器上它显然也被签名了。因此它可以包含 -128 到 +127 范围内的值。
0xff 是十进制的 255,一个不能用有符号字符表示的值。如果将 0xff 分配给带符号的字符,则该位模式最终不会被解释为 255,而是 -1。 (同样,如果您指定 0xfe,则不会将其解释为 254,而是 -2。)
0xffff 是十进制的 65535,这个值不能用 int16_t
表示。如果将 0xffff 分配给 int16_t
,该位模式最终不会被解释为 65535,而是 -1。 (同样,如果您分配 0xfffe,则不会将其解释为 65534,而是 -2。)
所以当你说
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
和 array4
的值不会相同。
另一个回答说 "there is no type information in C at runtime"。这是真的,但在这种情况下具有误导性。当编译器生成代码来操作 array1
、array2
、array3
和 array4
的值时,它生成的代码(当然 是 在运行时很重要!)将基于它们的类型。特别是,当生成代码以从 array1
和 array2
获取值时(但 而不是 array3
和 array4
),编译器将在分配给更大类型的对象(例如 32 位)时,使用执行 符号扩展 的指令。这就是 0xff 和 0xffff 变成 0xffffffff 的方式。
因为 C 在运行时 中没有类型信息,并且通过使用普通的 %x
进行打印,您告诉 printf
您的指针指向一个 unsigned int
。糟糕的库函数只是相信你...请参阅 printf(3)
中的 长度修饰符 以了解如何为 printf
提供所需的信息。
使用 %x
打印负值会导致 undefined behaviour,因此您不应假设您所看到的内容是合理的。
char
的正确格式说明符是 %hhd
,int16_t
的正确格式说明符是 "%" PRId16
。您将需要 #include <inttypes.h>
来获取后一个宏。
由于默认参数促销,将%d
与char
和int16_t
一起使用也是正确的1。如果您将代码更改为使用 %d
而不是 %x
,它将不再表现出未定义的行为,并且结果将是有意义的。
1 C 标准实际上并没有这么说,但假定那是作者的意图。