c - Char和int16数组元素都显示为32位十六进制



在下面的例子中:

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

为什么为charint16_t打印32位值,为什么它们可以进行比较并被认为是相同的?

它们是相同的,因为它们都是-1的不同表示。

它们打印为32位的ff值,因为您在32位机器上使用%d,并且默认参数提升发生了(基本上,所有较小的参数都被提升为int)。尝试使用%hx。(这可能会让你得到ffff;我不知道有什么方法可以得到ff,除了使用unsigned char,或者用& 0xff屏蔽:printf("%x n", array2[0] & 0xff)。)


展开"它们是相同的,因为它们都是-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 == *array2array1[0] == array2[0]


同样,值得注意的是,所有这些都很大程度上是因为array1array2的类型。如果你改成

uint16_t array3[] = {0xffff,0xffff,0xffff,0xffff};
unsigned char array4[] = {0xff,0xff,0xff,0xff};

您将看到打印不同的值(ffffff),并且array3array4的值不会进行相同的比较。

另一个回答说"在运行时C语言中没有类型信息"。这是事实,但在这种情况下是误导。当编译器生成代码来操作array1array2array3array4中的值时,它生成的代码(当然在运行时是重要的!)将基于它们的类型。特别是,当生成从array1array2获取值的代码时(但不是 array3array4),编译器将在赋值给更大类型的对象(例如32位)时使用执行符号扩展的指令。这就是为什么0xff和0xffff变成了0xffffff

因为在运行时C 中没有类型信息,并且通过使用普通的%x进行打印,您告诉printf您的指针指向unsigned int。差劲的库函数信任你…参考printf(3)中的长度修饰符,了解printf需要的信息

使用%x打印负数会导致未定义的行为,所以你不应该假设你所看到的有任何合理的东西。

char的正确格式说明符是%hhd, int16_t的正确格式说明符是"%" PRId16。您将需要#include <inttypes.h>来获取后一个宏。

由于默认参数提升,因此将%dcharint16_t 1一起使用也是正确的。如果您将代码更改为使用%d而不是%x,它将不再显示未定义的行为,并且结果将是有意义的。


1 C标准实际上并没有这么说,但假设这是作者的意图。

相关内容

  • 没有找到相关文章

最新更新