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格式控制符输出
好的,问题又来了,有符号数打印结果是-1似乎可以让人信服,为什么无符号数打印结果是负数?先换个思路,可能是格式控制符的问题,这里我们用的是%d
,那么如果换成专门打印无符号数的%u
会怎么样?
图2 %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;
查看上述代码的反汇编得到以下结果
- x转化到y进行了符号拓展,所以y=[ebp-8]=0xFFFFFFFF
- z转化到k进行了类似于
MOVZX
的转换,所以z=[ebp-10h]=0x000000FF
小结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");
}
查看反汇编:
小结2
- 含有不同类型的表达式在运算时会扩展到4字节进行运算,在扩展时其实就遵循了小结1里的规则。
printf()
在打印整型变量时,会先扩展成4字节。
读者可以尝试如下代码:
char x = -1;
printf("%u",x);
提示:如果x不扩展,打印结果应该为255
结论
- 修饰符
unsigned
与signed
并不在编译器层面限制整数类型中存储的数值,signed
修饰的类型也可以存储超过有符号数范围的正数,unsigned
修饰的类型也可以存储负数。 - 用
printf()
函数输出时,程序员使用格式控制符%d
或%u
告诉了函数按有符号数还是无符号数打印数值。 - 类型转换(小转大)时,根据小类型的修饰符来进行扩展。
- 表达式运算时,小类型会根据修饰符先进行零扩展或有符号扩展。
- 为避免这些奇奇怪怪的问题,建议用
unsigned
修饰的整数类型用%u
输出,没有用unsigned
修饰的类型用%d
输出。
C语言unsigned与signed使用辨析相关推荐
- C语言 unsigned与signed区别
我们来一起看下,C语言中,对于Integer Type(整数形式)的unsigned与signed两种形式的区别,以及在内存中的存储方式是如何的 Integer type(整数形式)是C语言中的基本数 ...
- C语言的补码表示和unsigned及signed的转换
这东西实际编程时一直无视的,范围小了就换个大点的表示形式,但是总觉得基础知识还是掌握得好,免得到时候用移位运算或类型转换或笔试题时要花时间想. C语言的基本类型有char.int.float.doub ...
- c语言 int是signed,C语言的补码表示和unsigned及signed的的转换
这东西实际编程时一直无视的,范围小了就换个大点的表示形式,但是总觉得基础知识还是掌握得好,免得到时候用移位运算或类型转换或笔试题时要花时间想. C语言的基本类型有char.int.float.doub ...
- c语言unsigned int 范围,unsigned int 32比特数据范围为-2147
提到unsigned,大家应该都了解,有朋友问c语言中unsigned什么意思,还有人想问c语言中的unsigned是什么意思,这到底是咋回事?事实上unsigned呢,下面是小编推荐给大家的unsi ...
- unsigned int mysql_mysql 中int类型字段unsigned和signed的探索
转自:http://www.0791quanquan.com/news_keji/topic_816453/ 探索一:正负数问题 拿tinyint字段来举例,unsigned后,字段的取值范围是0-2 ...
- int signed in mysql_【转】mysql 中int类型字段unsigned和signed的区别
转自https://www.cnblogs.com/wangzhongqiu/p/6424827.html 用法: mysql> CREATE TABLE t ( a INT UNSIGNED, ...
- C语言unsigned char、char与int之间的转换
C语言unsigned char.char与int之间的转换 2016年10月23日 18:40:50 bladeandmaster88 阅读数:11347更多 个人分类: c语言基础 先来看一道题: ...
- mysql中signed是什么类型_mysql 中int类型字段unsigned和signed的探索
转自:http://www.0791quanquan.com/news_keji/topic_816453/ 探索一:正负数问题 拿tinyint字段来举例,unsigned后,字段的取值范围是0-2 ...
- Unsigned与Signed关键字
Unsigned与 Signed 关键字 Signed: 在默认情况下声明的整型变量都是有符号的类型(char 有点特别),如果需声明无符号类型的话就需要在类型前加上 unsigned .无符号版 ...
最新文章
- 慕课《深入理解计算机系统》袁林枫老师章节测试1-9
- NTU商汤提出新 loss!提升图像重建和图像合成的质量 (ICCV2021)
- php人才招聘系统描述,基于ThinkPHP框架的人才招聘网站系统PHP源码
- 【期望】期望分数(金牌导航 期望-4)
- 保护系统 用数据库加密实现数据安全
- 数据结构之栈的应用(算术计算)
- weblogic 正在启动 wsee服务_详解LINUX安装部署weblogic集群--第二部分
- 链接地址中的target=”_blank”属性安全性处理
- #36328;#36234;#23457;#26680;#26426;#21046;#30340;gladder#25554;#20214;
- win10右键一直转圈_win10投屏不能使用的解决办法
- 计算机9针485接口,串口RS232__485的9针引脚定义
- 常用的十大塑料成型工艺(优缺点介绍)
- query.recordcount 总是为-1 解决方法
- word打开总是安装解决方法
- MA5626 MA5821 POE供电版开启POE供电高优先级配置指导
- KubeSphere 添加NFS存储
- 法国“毁容”女教师请求安乐死
- 系统架构师(十)设计模式
- [CocosCreator]使用龙骨DragonBone
- ffmpeg yasm not found, use --disable-yasm for a crippled build
热门文章
- java语言程序设计(新手篇)
- 欧拉计划(project euler)最详细中文题解
- 技术交底书怎么撰写?看这一篇就够了
- 暴涨买卖有望趋势线顶底选股公式 通达信波段趋势顶底指标
- notebook pip install 只有星号_世界上最小的船,只有四个红细胞那么长丨一周科技...
- VS Code如何配置C\C++环境 步骤详解
- dra7xx cpu frequency change
- scanpy去除批次效应
- Oracle 批量插入(insert all into)
- 棋牌开发需要注意哪些事项