繁体   English   中英

使用%u读取签名的字符

[英]Reading signed char using %u

#include <stdio.h>

int main() {
    int i,n;
    int a = 123456789;

    void *v = &a;

    unsigned char *c = (unsigned char*)v;

    for(i=0;i< sizeof a;i++) {
        printf("%u  ",*(c+i));
    }

    char *cc = (char*)v;
    printf("\n %d", *(cc+1));

    char *ccc = (char*)v;
    printf("\n %u \n", *(ccc+1));

}

该程序在我的32位Ubuntu机器上生成以下输出。

21  205  91  7  
-51
4294967245

前两行输出我能理解=>

  • 第1行 :在内存中存储字节的顺序。
  • 第二行 :第二个字节值的有符号值(2的补码)。
  • 第3行 :为什么这么大的价值?

请解释最后一行输出。 为什么添加三个1的字节,因为(11111111111111111111111111001101) = 4294967245

显然你的编译器使用有符号字符,它是一个小尾数,二进制补码系统。

123456789d = 075BCD15h
Little endian: 15 CD 5B 07

因此v + 1给出值0xCD 当它存储在signed char中时,您将获得带符号十进制格式的-51

当传递给printf时,包含值-51的字符*(ccc+1)首先被隐式类型提升为int ,因为像printf这样的可变参数函数有一条规则说明所有小整数参数都会被提升为int默认参数提升 ) 。 在此促销期间,标志将被保留。 您仍然具有值-51,但对于32位有符号整数,这将给出值0xFFFFFFCD

最后, %u说明符告诉printf将其视为无符号整数,因此最终得到4.29 bil。

这里要理解的重要部分是%u与实际类型提升无关,它只是告诉printf如何在提升解释数据。

-51以8位十六进制存储为0xCD (假设2s恭维二进制系统)

当你将它传递给像printf这样的可变函数时 ,会发生默认参数提升,并将char提升为int ,表示为0xFFFFFFCD (对于4字节int)。

解释为int 0xFFFFFFCD-51并解释为unsigned int4294967245

进一步阅读: C函数调用中的默认参数提升


请解释最后一行输出。 为什么添加三个1的字节

这称为符号扩展 当较小的有符号数被分配(转换)为较大的数字时,其符号位被复制以确保它代表相同的数字(例如1s和2s补码 )。


错误的printf格式说明符
您正在尝试使用指定unsigned [int] "%u"打印一个char ,指定unsigned [int] printf中的转换说明符不匹配的参数是7.19.6.1第9段中的未定义行为。

如果转换规范无效,则行为未定义。 如果任何参数不是相应转换规范的正确类型,则行为未定义。

使用char来存储签名值
另外,为了确保char包含有signed值,显式使用signed char作为char可以表现为signed charunsigned char (在后一种情况下,您的代码段的输出可能是205 205 )。 gcc您可以使用-funsigned-char选项强制char表现为unsigned char

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM