作者:autogeek

原文链接:http://www.cnblogs.com/autogeek/p/4321635.html

1.先从一个列子引出问题:

//sample_1 unsigned char 
#include <stdio.h>
#include <stdlib.h> int main()
{
unsigned char a = 255;
a = a + 1;
printf("a = %d\n", a);
return 0;
}

输出结果:

为什么是0 而不是256, 这是很显然的发生了溢出。现在从机器存储的角度来看这个问题:

在C语言中,char表示占用一个byte空间,在机器上一个byte可存储的范围是0000 0000 b ~ 1111 1111 b, 现在不考虑符号问题,仅仅把它解释为无符号的整数,那么对应十进制范围是0 ~ 255, 现在我们的a初始值是255 即 1111 1111 b,接着给它加1,那么二进制运算后变为 1 0000 0000 b, 由于进位,结果变成了9个bit,但是别忘了char是只占一个byte的,所以最前面的那个bit 将会被丢弃,结果变成 0000 0000 b, 因此输出结果会是0.

这个列子说明,整数在机器上存储的方法是满足二进制的运算律的,但是当用一定类型表示出来时,这个二进制的值就要按照那个类型的约束表现出来,就像上面的列子一样,即使最后的二进制结果是9个bit,但是char类型明确约束你只能占8个bit,最后只能丢弃1个bit之后按8个bit的结果展示出来。

 

2.第二个列子,引入有符号类型的表示问题:

//sample_2 signed char

#include <stdio.h>
#include <stdlib.h> int main()
{
char a = 127;
a = a + 1; printf("a = %d\n", a);
return 0;
}

输出结果:

先不忙分析问题原因,先来搞清楚负数是如何在计算机上存储的。简单的说,计算机擅长做0和1的加法,并不愿意像人类用的十进制一样去引入负号这个东西,否则会增加硬件和软件的复杂性和成本,如何解决这个问题,众所周知的就是用补码。可以举个列子去理解补码的作用,1+(?)= 0,很显然 1 + (-1)= 0, 这样就把减法问题转化为加法问题,那么在计算机中怎么去表示(-1)? 同样的,我们站在计算机的角度想问题(先拿一个byte的来举例),(0000 0001 b) + (?) = (0000 0000 b), 当然是(0000 0001 b) + (1111 1111 b) = (0000 0000 b),因此(1111 1111 b) 就是十进制1(原码)的补码,教科书中说补码可以通过对原码取反加一得到,其实通过上面的列子可以换一种角度解读补码的含义:即补码就是那个使得和原码相加之后结果能够为0的数。说了这么多,就是想说明对一个byte来说,(-1)在计算机上存储为(1111 1111 b)。

那么对于有符号char型来说,还是一个byte的空间,还是0000 0000 b ~ 1111 1111 b的范围,但是现在要把这个范围按有符号整数的表示来翻译了,可以分为3部分来理解,即 < 0,0 ,> 0,0000 0000 b显然是0, 0000 0001 b ~ 0111 1111 b显然是 1 ~ 127, 1000 0000 b ~ 1111 1111 b 是 –1 ~ –128。由此也可以发现,可以把最高位作为符号位来理解,0正1负。

换一种表达方式 (图画的太渣了,求推荐好的画图工具)

上面这两张图希望能表达清楚我上面的分析结论,即计算机上存储的整数一定是满足二进制的运算律的,但是怎么去解释它就取决于整型变量的类型约束条件了。

说了这么多,再来解释第二个列子就简单多了。第一步char a = 127 说明a是有符号的,127在计算机上存储为0111 1111b, 第二步 a = a + 1,a在计算机上变成了1000 0000b, 对应上面的分析,把它按照有符号数来解释即 -128,因此输出-128。

 

3.上第三个列子,关于符号位扩展问题:

//sample_3

#include <stdio.h>
#include <stdlib.h> int main()
{
char a = 127;
a = a + 1; printf("a = %u\n", a);
return 0;
}

输出结果:

我只是将sample_2的代码中%d改成了%u,输出结果就差之千里,其实还是一个道理,用不同的方式解释计算机存储的二进制值就会得到不同的结果。当然这里还涉及符号位扩展以及类型提升。

首先说类型提升,%d表示打印int类型有符号十进制数,%u表示打印int无符号十进制数,当a被打印时隐式的发生类型提升,即char被提升为int,即8位被扩展为32位。

对于sample_3来说:

a的值在1个byte中,是 0111 1111b

a加1后在1个byte中,是 1000 0000b

a的值被类型提升并扩展为4个byte后,是11111111 11111111 11111111 10000000 b,按照%u来解释是多少呢,当然是4294967168。

可是为什么扩展后前面的空位都是补1而不是补0呢,这个有个原则是 “有符号数扩展符号位,也就是向前补1,无符号数扩展0”。

那么sample_2应该也发生类型提升和符号扩展,为什么没出问题呢。因为虽然a的值被类型提升并扩展为4个byte后,依然是11111111 11111111 11111111 10000000 b,按照%d来解释,他是00000000 00000000 00000000 10000000 b的补码,所以表达为-128。

以上是自己的一些理解,难免有错误,欢迎讨论。

对C语言整数类型的一点理解的更多相关文章

  1. C语言-整数类型

    C语言-整数类型 整数类型 Reg为寄存器 字长,是说这个寄存器是多少宽的,每个寄存器可以表示32bit数据,也是说CPU与RAM每一次传递的数据也是32bit 计算机内部一切都是二进制 所有的类型, ...

  2. C语言整数类型在X86和X64下的字节大小

    C声明 32位机器(X86) 64位机器(X64) char 1 1 short int 2 2 int 4 4 long int 4 8 long long int 8 8 char * 4 8 f ...

  3. 如何用一个语句判断一个整数是不是二的整数次幂——从一道简单的面试题浅谈C语言的类型提升(type promotion)

    最近招聘季,看JULY大哥的面试100题时,碰到这么一个扩展问题: 如何用一个语句判断一个整数是不是二的整数次幂?(此题在编程之美也有) easy, 2的整数次幂的二进制形式只有一个1,只要用i和i- ...

  4. C语言三种整数类型

    1,int 是 C 语言的基本整数类型,可以满足我们处理一般数据的需求. C 语言还提供了四个可以修饰 int 的关键字:short.long.signed,以及 unsigned. 利用这四个关键字 ...

  5. C语言基础学习基本数据类型-其他整数类型

    其他整数类型 初学C语言时,int类型会满足你对整数的大多数需求. C语言还提供了三个关键字用以修饰基本的整数类型:short.long和unsigned.有以下几个注意点: (1)C语言没有具体规定 ...

  6. RxSwift 入坑好多天 - 终于有了一点理解

    一.前言 江湖上都在说现在就要赶紧学 swift 了,即将是 swift 的天下了.在 api 变化不大的情况下,swift 作为一门新的语言,集众家之所长,普通编码确实比 oc 要好用的多了 老早就 ...

  7. C语言的类型大小

    C语言的类型大小 设计程序的时候我们一般会考虑的尽量的周全,尤其是像C这样的静态类型语言. 有一些溢出的问题就源于没有搞清楚变量的大小范围,所以我们编写的时候需要特别注意 C的整形(整数类型)大小 C ...

  8. C语言常见类型占用字节数

    前言 最近笔试经常遇到c语言各类型变量所占字节数的问题,这里做一个总结好了. 类型 常见的有char.int.long.short.float.double及指针等. 字符类型 这里单只char,ch ...

  9. [改善Java代码]用整数类型处理货币

    建议22:用整数类型处理货币. public class Client { public static void main(String[] args) { System.out.println(&q ...

随机推荐

  1. 打包一份py给大家用!!!

    好不容易写完了代码,却发现对面无法使用自己的python代码,其无奈可想而知 在这里就给大家介绍一下pyinstaller的简单用法 你所需要的就是在电脑上安装好 https://blog.csdn. ...

  2. Java入门 - 高级教程 - 06.邮件收发

    原文地址:http://www.work100.net/training/java-email.html 更多教程:光束云 - 免费课程 邮件收发 序号 文内章节 视频 1 概述 2 发送一封简单的邮 ...

  3. Java单体应用 - 架构模式 - 01.三层架构

    原文地址:http://www.work100.net/training/monolithic-architecture-3level.html 更多教程:光束云 - 免费课程 三层架构 序号 文内章 ...

  4. 电脑开机后多了OneKey Ghost启动选项怎么解决

    原文地址:http://www.xitongcheng.com/jiaocheng/dnrj_article_18745.html 大多数用户在使用OneKey Ghost安装电脑系统后,会在开机启动 ...

  5. axios用post传参,后端无法获取参数问题

    最近用vue+nodejs写项目,前端使用axios向后台传参,发现后台接收不到参数. 后台是node+express框架,然后使用了body-parser包接收参数,配置如下: const expr ...

  6. C/C++画一个巨型五角星

    把朱老师拉着画了半天 利用正弦定理判断一个点是否是否在五角星内,相对于五角星中心的四个象限特判一下来修改角度,把角度都转化成最上面的角,就差不多了,没仔细调整五角星位置,很丑 当然其实也有更方便的方法 ...

  7. Shell之信号捕获

    前言 当我们在运行某一段代码的时候,希望有类似事物一样的操作,要么成功,要么失败:一般的shell脚本都是自上而下,从左之后运行,碰到异常信号就会出错,从而终止脚本的运行,这个时候脚本可能运行到某一处 ...

  8. springboot中使用Caffeine本地缓存

    Caffeine是使用Java8对Guava缓存的重写版本性能有很大提升 一 依赖 <dependency> <groupId>org.springframework.boot ...

  9. 双括号(()),shell与C++的桥梁

    使用语法: ((表达式))用来扩展Shell中的算术运算,以及赋值运算,扩展for,while,if条件测试运算. 注意点: 1.在双括号结构中,所有的表达式可以像c语言一样,如a++,b-- 2.在 ...

  10. Maven: 互联网开发常用的jar以及版本pom.xl文件

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/20 ...