1

在下面的示例中:

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

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

4

3 回答 3

5

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

它们打印为 32 位的价值,ff因为您在 32 位机器上并且您使用%d并且发生了默认参数提升(基本上,所有较小的都被提升为int)。尝试使用%hx. (这可能会让你明白ffff;我不知道ff除了使用 : 或掩蔽之外还有什么unsigned char方法可以到达这里。)& 0xffprintf("%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 分配给 a 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]


此外,值得注意的是,所有这些都很大程度上是因为 和 的array1类型array2。如果你改为说

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

您会看到打印的不同值 (ffffff),并且来自array3和的值array4不会比较相同。

另一个答案指出“C 在运行时没有类型信息”。这是真的,但在这种情况下具有误导性。当编译器生成代码来操作来自array1array2array3和的值时,array4它生成的代码(这在运行时当然重要!)将基于它们的类型。特别是,当生成代码以从array1and array2(但不是 array3and )中获取值时,编译器将使用在分配给更大类型(例如 32 位)对象时array4执行符号扩展的指令。这就是 0xff 和 0xffff 变成 0xffffffff 的方式。

于 2015-07-22T12:06:24.487 回答
1

因为在运行时C 中没有类型信息,并且通过使用纯文本%x进行打印,printf所以您告诉指针指向unsigned int. 糟糕的库函数只是信任您……请参阅Length 修饰符printf(3)了解如何提供printf所需的信息。

于 2015-07-22T12:07:25.910 回答
1

使用%x打印负值会导致未定义的行为,因此您不应假设您所看到的内容有任何合理性。

charis%hhd和 for int16_tit is的正确格式说明符"%" PRId16。您将需要#include <inttypes.h>获取后一个宏。

由于默认参数 Promotions%d ,使用withcharint16_t 1也是正确的。如果您将代码更改为使用%d而不是%x,它将不再表现出未定义的行为,并且结果将是有意义的。


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

于 2015-07-22T23:35:25.117 回答