Printf的符号扩展问题

今天看别人发了一段代码问输出的结果

#include <stdio.h>

int main()
{
    char a = 0xb6;
    short b = 0xb600;
    int c = 0xb6000000;

    printf("sizeof char = %d\n", sizeof(char));
    printf("sizeof short = %d\n", sizeof(short));
    printf("sizeof int = %d\n", sizeof(int));

    printf("a =  %#x %d\n", a, a);
    printf("b = %#x %d\n", b, b);
    printf("c = %#x %d\n", c, c);

    return 0;
}

输出结果为:

 这就出现很多疑问了:

1.a是char类型的占一个字节 b是short类型的占两个字节  为什么在赋了十六进制的值后变成了4个字节的值?

2.有符号整数在内存中不是通过补码的形式保存的吗 ?那a使用%#x打印出来的十六进制不应该是-74的补码(0xb6)吗?为什么是0xff ff ff b6?

把变量a b c都换成unsigned类型的变量 就会正常输出 这是为什么?

#include <stdio.h>

int main()
{
    unsigned char a = 0xb6;
    unsigned short b = 0xb600;
    unsigned int c = 0xb6000000;

    printf("sizeof char = %d\n", sizeof(char));
    printf("sizeof short = %d\n", sizeof(short));
    printf("sizeof int = %d\n", sizeof(int));

    printf("a =  %#x %d\n", a, a);
    printf("b = %#x %d\n", b, b);
    printf("c = %#x %d\n", c, c);

    return 0;
}

难道对于一个有符号的负整数 会用四字节来存储 多余的位都用1来填充?

可以这么理解。

先来看看chatgpt的回答:

由于 char 类型默认是有符号类型,因此在将 a 的值作为参数传递给 printf 函数时,会发生符号扩展,即将 a 的符号位扩展到更高的位,以保持其原有的符号。因此最终输出的结果是符号扩展后的值 0xffffffb6。具体来说,a 实际上存储的是一个有符号整数 -74(0xb6 的补码表示),而不是无符号整数 182。当您使用 %x 格式符将 a 打印出来时,由于 a 是有符号整数,其在内存中存储的是一个 8 位的二进制补码,printf 函数在将其转换为十六进制字符串时,会将这个有符号整数先转换为无符号整数,然后再将其打印出来。这样做是为了保证打印出来的结果的一致性。因此,在将 -74 转换为无符号整数时,会使用符号扩展(sign extension)将其扩展为一个 32 位的无符号整数 0xffffffb6,而不是原来的 0xb6。这就是您看到的输出结果中出现 0xffffff 的原因。
如果您将 a 定义成无符号 char 类型,即使用 unsigned char a = 0xb6 进行定义,则 printf 函数在将 a 打印出来时,不会进行符号扩展,因此打印结果为 0xb6。

说人话:就是由于内存中保存整数是通过补码的形式来保存的,所以我们使用printf(%x)来打印时打印的是 对应变量的值的补码 ,但是由于printf的工作机制它需要将不管是有符号变量还是无符号变量的值的补码都强制转化成无符号的值的补码 这是为了方便将其转换成字符串然后在标准输出流中打印出来,这是就会出现问题有符号和无符号都强制转化成了无符号 那怎么保证打印出来的补码是正确的?

为了加以区分(因为无符号数补码是它本身 有符号数的补码则是将其除符号位外取反再加1):

使用printf(%x)打印的数

1.如果该变量是有符号数 将会对其补码进行符号拓展 将其拓展为4字节 且除了原本的数据位其余高位都与符号位相同 比如0xb6 会拓展为 0xff ff ff b6  0x1会拓展为 0x 00 00 00 01 既还是0x1

2.如果该变量是无符号数 就直接输出该变量数值的补码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值