在数学中,数字有正负之分。在C语言中也是一样,short、int、long 都可以带上正负号,示例

//负数
short a1 = -10;
short a2 = -0x2dc9;  //十六进制
//正数
int b1 = +10;
int b2 = +0174;  //八进制
int b3 = 22910;
//负数和正数相加
long c = (-9) + (+12);

如果不带正负号,默认就是正数。

符号也是数字的一部分,也要在内存中体现出来。符号只有正负两种情况,用1位(Bit)就足以表示;C语言规定,把内存的最高位作为符号位。以 int 为例,它占用 32 位的内存,0~30 位表示数值,31 位表示正负号。

 在编程语言中,计数往往是从0开始,例如字符串 "abc123",我们称第 0 个字符是 a,第 1 个字符是 b,第 5 个字符是 3。这和我们平时从 1 开始计数的习惯不一样,大家要慢慢适应,培养编程思维。

C语言规定,在符号位中,用 0 表示正数,用 1 表示负数。 int 类型的 -10 和 +16 在内存中的表示为:


short、int 和 long 类型默认都是带符号位的,符号位以外的内存才是数值位。如果只考虑正数,那么各种类型能表示的数值范围(取值范围)就比原来小了一半。

但是在很多情况下,我们非常确定某个数字只能是正数,比如班级学生的人数、字符串的长度、内存地址等,这个时候符号位就是多余的了,就不如删掉符号位,把所有的位都用来存储数值,这样能表示的数值范围更大(大一倍)。

C语言允许我们这样做,如果不希望设置符号位,可以在数据类型前面加上 unsigned 关键字。

示例

unsigned short a = 12;
unsigned int b = 1002;
unsigned long c = 9892320;

这样,short、int、long 中就没有符号位了,所有的位都用来表示数值,正数的取值范围更大了。这也意味着,使用了 unsigned 后只能表示正数,不能再表示负数了。

如果将一个数字分为符号和数值两部分,那么不加 unsigned 的数字称为有符号数,能表示正数和负数,加了 unsigned 的数字称为无符号数,只能表示正数。

注意,如果是unsigned int类型,那么可以省略 int ,只写 unsigned,例如:

unsigned n = 100;

它等价于:

unsigned int n = 100;

无符号数的输出

无符号数可以以八进制、十进制和十六进制的形式输出,它们对应的格式控制符分别为:

严格来说,格式控制符和整数的符号是紧密相关的,具体就是:

 %d 以十进制形式输出有符号数;%u 以十进制形式输出无符号数;%o 以八进制形式输出无符号数;%x 以十六进制形式输出无符号数。

那么,如何以八进制和十六进制形式输出有符号数呢?很遗憾,printf 并不支持,也没有对应的格式控制符。在实际开发中,也基本没有“输出负的八进制数或者十六进制数”这样的需求,我想可能正是因为这一点,printf 才没有提供对应的格式控制符。

不同类型的整数,以不同进制的形式输出时对应的格式控制符(–表示没有对应的格式控制符)。

之前我们也使用 %o 和 %x 来输出有符号数了,为什么没有发生错误呢?这是因为:
当以有符号数的形式输出时,printf 会读取数字所占用的内存,并把最高位作为符号位,把剩下的内存作为数值位;
当以无符号数的形式输出时,printf 也会读取数字所占用的内存,并把所有的内存都作为数值位对待。

对于一个有符号的正数,它的符号位是 0,当按照无符号数的形式读取时,符号位就变成了数值位,但是该位恰好是 0 而不是 1,所以对数值不会产生影响,这就好比在一个数字前面加 0,有多少个 0 都不会影响数字的值。

如果对一个有符号的负数使用 %o 或者 %x 输出,那么结果就会大相径庭。

可以说,“有符号正数的最高位是 0”这个巧合才使得 %o 和 %x 输出有符号数时不会出错。

再次强调,不管是以 %o、%u、%x 输出有符号数,还是以 %d 输出无符号数,编译器都不会报错,只是对内存的解释不同了。%o、%d、%u、%x 这些格式控制符不会关心数字在定义时到底是有符号的还是无符号的:
你让我输出无符号数,那我在读取内存时就不区分符号位和数值位了,我会把所有的内存都看做数值位;
你让我输出有符号数,那我在读取内存时会把最高位作为符号位,把剩下的内存作为数值位。

下面的代码进行了全面的演示:

#include <stdio.h>
int main()
{short a = 0100;  //八进制int b = -0x1;  //十六进制long c = 720;  //十进制unsigned short m = 0xffff;  //十六进制unsigned int n = 0x80000000;  //十六进制unsigned long p = 100;  //十进制//以无符号的形式输出有符号数printf("a=%#ho, b=%#x, c=%ld\n", a, b, c);//以有符号数的形式输出无符号类型(只能以十进制形式输出)printf("m=%hd, n=%d, p=%ld\n", m, n, p);return 0;
}

运行结果:

a=0100, b=0xffffffff, c=720
m=-1, n=-2147483648, p=100

对于初学者来说,b、m、n 的输出结果看起来非常奇怪,甚至不能理解。按照一般的推理,b、m、n 这三个整数在内存中的存储形式分别是:

当以 %x 输出 b 时,结果应该是 0x80000001;当以 %hd、%d 输出 m、n 时,结果应该分别是 -7fff、-0。但是实际的输出结果和我们推理的结果却大相径庭,这是为什么呢?
注意,-7fff 是十六进制形式。%d 本来应该输出十进制,这里只是为了看起来方便,才改为十六进制。

其实这跟整数在内存中的存储形式以及读取方式有关。b 是一个有符号的负数,它在内存中并不是像上图演示的那样存储,而是要经过一定的转换才能写入内存;m、n 的内存虽然没有错误,但是当以 %d 输出时,并不是原样输出,而是有一个逆向的转换过程(和存储时的转换过程恰好相反)。

也就是说,整数在写入内存之前可能会发生转换,在读取时也可能会发生转换,而我们没有考虑这种转换,所以才会导致推理错误。

如果感觉不错的话请点赞哟!!!

C语言中的正负数及其输出相关推荐

  1. c语言int2字节负数类型范围,C语言中的正负数以及数值溢出

    C语言中的正负数以及数值溢出 在数学中,数字有正负之分.在C语言中也是一样.下面是小编分享的C语言中的正负数以及数值溢出,欢迎大家参考! 在C语言中,short.int.long 都可以带上符号,例如 ...

  2. 计算机中的正负数表示

    计算机中的正负数表示 在32位系统中,int类型占4个字节,一共是32个2进制位,int类型的首位是符号位,0代表正数,1代表负数,int的最大值是0x7fffffff(即除了最高的1Bit其他31位 ...

  3. c语言对浮点数的处理默认是double吗,C语言中浮点数float和double输出的问题

    C语言中浮点数float和double输出的问题 关注:260  答案:6  信息版本:手机版 解决时间 2019-01-12 07:33 斑駁影 2019-01-11 09:20 #includev ...

  4. C语言中汉字的存储和输出

    C语言中汉字的存储和输出 #include<stdio.h> int main() { int b,a=0; char c[]={"我是"}; //在数组存储为{&qu ...

  5. c语言中字符串的子式咋样输出,C语言常用代码

    <C语言常用代码>由会员分享,可在线阅读,更多相关<C语言常用代码(48页珍藏版)>请在人人文库网上搜索. 1.WORD格式-可编辑-#includeusing namespa ...

  6. C++实现包含空格、标点、字符、数字的字符串的逆序输出,并且还可以实现一句语言中每个单词的倒序输出

    简介:本C++代码能够实现任意输入的字符的逆序输出,代码的后半部分可以实现一句英文语句的单词的倒序输出. #include <iostream> #include <string&g ...

  7. c语言对浮点数截断,C语言中浮点数精度进行截断输出

    今日在做ACM/ICPC的题目时,遇到了这样的情况:程序求得的结果是一个浮点数,但题目要求以整数形式输出(取不小于该结果的最小整数).这是个很简单的问题.也许很多人会采用float强制转型为int再加 ...

  8. C语言中实现十进制转二进制输出

    众所周知,C中以八进制,十进制和十六进制都可以通过%d,%o和%x轻松实现,然而唯独没有提供二进制输出的快速方式.博主整理出两种简单的实现方式,供参考. 方法一:itoa函数 itoa函数将数值转换为 ...

  9. C语言中文件操作使用fgetc()输出出现多余空格问题

    #include<stdio.h> int main() { //定义文件指针 FILE *fp; char ch; int word=0,num=0,oth; if((fp=fopen( ...

最新文章

  1. php导出页面word,php导出生成word的方法_PHP
  2. mos管电路_【鼎阳硬件智库原创︱电源】 MOS管驱动电路的设计
  3. 【编程题目】求二叉树中节点的最大距离
  4. 泛型lua的for循环以及lua的特殊的dowhile循环
  5. html超市代码,前端 CSS : 5# 纯 CSS 实现24小时超市
  6. AliOS Things全链路优化-CoAP FOTA
  7. 关于物联网规则引擎技术,你想要知道的都在这儿!
  8. oracle+long列,oracle中对LONG列进行查询
  9. windows环境下unicode编程总结
  10. hive-2.3.3安装指北
  11. 大数据之多数据源综合管理系统:数据源配置管理
  12. 中英文切换_值得收藏|不重装软件实现ArcGIS中英文版本之间切换
  13. 揭开 Java 注解的神秘面纱
  14. awl 多线程SYN***工具0.2版[转]
  15. Python系列-Django-Ninja
  16. 昂达V820W使用指南
  17. 6年全栈工程师回答:web前端的主要学习什么,现在还有前途吗?一般工资是多少?
  18. 中国科学院计算机所研究生实习,在中科院计算所实习的一年(更新中。。)
  19. 华硕Android原始密码,华硕(ASUS)路由器默认密码是多少?
  20. java 移动平均_EWMA之——EWMA指数加权移动平均模型的Java实现

热门文章

  1. 完全相同的4个小矩形如图所示放置_分享 | 你想知道的100个桥梁知识点!
  2. 诺禾致源css客户端,诺禾,诺禾致源:CSS 基础教学
  3. c mysql 双主复制_mysql双主复制及使用keepalived作高可用的配置详解
  4. Android平台实现Unity3D下RTMP推送
  5. Java字符串池(String Pool)深度解析
  6. matlab compiler 与matlab coder 区别,MATLAB编译器与MATLAB编码器
  7. 战地2服务器怎么虚拟人数,战地2怎么修改作战人数?
  8. C语言6F多少,求助!!请人帮忙画C语言程序流程图.紧急!!!
  9. 华为服务器双系统教程,服务器上安装双系统
  10. 常见排序之——插入排序