C语言unsigned与signed使用辨析 |
您所在的位置:网站首页 › c语言整型变量取值范围 › C语言unsigned与signed使用辨析 |
一些说明
操作系统: windows xp x32编译器:VC++ 6.0测试只针对整型变量,因为浮点型变量的IEEE存储方式本身就包含了符号位。
使用场景
定义一个整型变量x;,如果我们会在x中存储有符号数,则定义(signed) int x;(signed可以省略),如果只会存储无符号数则定义为unsigned int x;。 很多书上都是这么写:
有符号int取值范围:-2,147,483,648~2,147,483,647 无符号int取值范围:0~4,294,967,295 Q1:unsigned修饰的类型只能存储无符号数,signed修饰的类型只能存储有符号数? 口说无凭,还是以int类型为例,分别存储超过取值范围的数据到变量中 int x = 4294967295; unsigned int y = -2147483648;经VC 6.0编译通过,表明修饰符signed与unsigned并没有在编译器层面进行限制。 理解:unsigned修饰符并不影响int类型的宽度(4个字节),用4个字节肯定可以表示有符号数或无符号数取值范围内的任意一个数,所以这样存储是没有问题的。那么如果printf()函数打印结果会怎么样? 好的,问题又来了,有符号数打印结果是-1似乎可以让人信服,为什么无符号数打印结果是负数?先换个思路,可能是格式控制符的问题,这里我们用的是%d,那么如果换成专门打印无符号数的%u会怎么样? 此时变量y的打印结果似乎正常了,但是变量x的打印结果又开始扑朔迷离。根据实践得出的结论是:当使用函数printf()打印时,格式控制符告诉编译器按什么数输出,%d表示按十进制有符号数输出,%u表示按十进制无符号数输出 有了以上结论,输出的怪异现象就很好解释了。在使用printf()函数打印输出时,使用%d还是%u是由程序员决定的,也就是说程序员决定了该数按什么规则处理输出。 两张截图输出结果解释: 图1中按十进制有符号数输出x和y,x=4294967295转换为16进制就是0xFFFFFFFF,对应有符号数-1,所以x输出-1;y = -2147483648本身就是有符号数中的最小的负数,所以直接输出。图2中按十进制无符号数输出x和y,x=4294967295是无符号数中最大的数,直接输出;y = -2147483648转换为正数就是2147483648(这里涉及到补码相关知识)。 Q2:基于以上结论,编译器并不对signed、unsigned修饰的变量取值进行限定,那么它们有什么用途? 用途1 类型转换在这之前先看两条汇编指令:MOVSX、MOVZX MOV AL,0FF ; AL=0FFMOVSX ECX,AL ; MOVSX中的S表示Sign 上述指令的意思是先将0FF赋值给寄存器AL,MOVSX ECX,AL就是将AL视作有符号数扩展到ECX,AL的最高位即为符号位,由于AL最高位为1,所以扩展后的前24位全为1,ECX=0xFFFFFFFF MOV AL,0FF ; AL=0FFMOVZX ECX,AL ; MOVZX中的Z表示Zero 上述指令的意思是先将0FF赋值给寄存器AL,MOVZX ECX,AL就是将AL视做无符号数扩展到ECX中,所以扩展过程直接在扩展后的前24位添0,ECX=0x000000FF看一个类型转换的例子 char x = 0xFF; int y = x; unsigned char z = 0xFF; int k = z;查看上述代码的反汇编得到以下结果 小结1 进行类型转换时,只与原类型本身有关,如果原类型加了unsigned修饰符则为MOVZX扩展,如果没有加unsigned则为MOVSX扩展。加不加unsigned决定了扩展时填充的是0还是1。 用途2 表达式运算 在表达式中出现不同类型的变量时,运算过程会转换成4字节宽度进行运算(针对整型变量) char x = 12; short y = 13; printf("%d\n",x+y); if (x+y>20) {printf(">20\n"); }查看反汇编: |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |