专栏首页轮子工厂4. C语言 -- 一个由数据类型和取值范围引发的 BUG

4. C语言 -- 一个由数据类型和取值范围引发的 BUG

(。・∀・)ノ゙嗨,失踪人口回归啦!!!

之前看到有人留言催更,老夫的心里的竟然有一丝惊喜和兴奋。上周说要改版嘛( 。_ 。) ✎然后我就紧赶慢赶出了这篇稿子,但是由于一些原因,在今天才与大家间面。

之前就有小伙伴留言说建议在上次的内容后面加上数据类型,反码补码等知识。我还很是激动的,居然猜出了我今天要讲的内容。

首先强调,忘记了上节课内容的同学一定要回顾下哦!在《3. C语言 -- 叫你一声你敢答应嘛》的 2.3 部分讲到 char 字符型,占用一个字节;而 int 整型,通常反映了所用机器中整数的最自然长度。那一个字节和机器中整数的最自然长度到底是多大的呢?今天就给大家介绍一下 C 语言中的数据类型和取值范围。

1

数据类型

在 C 语言里,数据类型即说明了它是什么类型的数据,也说明了所需的内存的大小,C 语言允许使用的类型如下:

在基本类型中的整数类型、浮点数类型和字符类型在之前介绍过了;其中的_Bool是布尔型,只能取 0 和 1 两个值;另一个是枚举类型(enum),这个类型将在后面的部分进行介绍。其余的数据类型,如指针类型、构造类型和空类型也将在后面的部分进行介绍。

1.1

数据类型的限定符

  • short , long, long long

我们可以为这些基本数据类型加上一些限定符,比如表示长度的 short long。比如 int 经过限定符修饰之后,可以是 short intlong int,还可以是 long long int。其中 short int表示所占内存比 int 小的数据类型,而 long int 表示所占内存比int 大的数据类型。

在 C 语言并没有限制 int 的大小,更没有限制 short int 等带限定符的数据类型的大小,只是规定了

short int<=int<=long int<=long long int

注意哦,是小于等于,不是小于哦!

  • signed 和 unsigned

还有一对类型限定符是 signedunsigned,它们用于限定 char 类型和任何 int 类型变量的取值范围。signed 表示该变量是带符号位的 (可以表示负数),而 unsigned 表示不带符号位 (只能表示正数)。默认所有的整型变量都是 signed 的,也就是带符号位的。

对于 int 类型的变量来说,有四种表示长度的限定符(除int本身外,还有 shortlonglong long),再加上符号位的限定signed unsigned,所以一共存在着 8 种int 类型的变量。

1.2

sizeof 运算符

sizeof 用于获得数据类型或表达式的长度,它有三种使用方式:

  • sizeof(type_name); //sizeof(类型) 即某一种类型的变量所占内存大小;
  • sizeof(object); //sizeof(对象) 即某一个对象所占内存大小;
  • sizeof object; //sizeof 对象 查看对象占用内存大小的另一种表达方式;

1.3 举例说明

下面的程序将使用sizeof输出每一种数据类型或者每一个变量在内存中所占的大小,具体地是使用8 种 int 类型的变量进行说明。

在 64 位的 Ubuntu 使用 gcc 编译执行上面的代码可以看到如下的结果

如上图所示,有许多的 Warning,根据提示可知,这是由于sizeof返回的是一个long unsigned int的变量,所以使用 %d作为占位符有可能溢出,修改方法是将上面的%d改为%ld。

分析输出的结果,通过第 1 行和第 2 行输出可以看出对于某一种数据类的变量,变量和数据类型的大小是相同的,这是很显然的;其次通过第 3 行到第 6 行可以看到,数据类型的长度满足上面的不等式

short int <= int <= long int <=long long int

的要求;通过最后两行可以看出,对于同一种数据类型,signedunsigned 只是最高位bit的意义,数据长度不会被改变的。

但是我们如果强制将无符号数赋值为负数呢?代码如下

输出的结果如下图所示

我们可以看到无符号数 b果然没有输出对应的 -1 ,但是为什么输出 65535 呢?这就与数据类型的取值范围有关了。

取值范围

2.1

比特与字节

CPU能读懂的最小单位是比特位,记为bit,b,只能取 0 1 两个数字;内存机构的最小寻址单位是字节,记为Byte,B。如下图所示,为字节和比特之间的关系

因此一个字节所能存储的最大数字是二进制的11111111。那这个二进制的数字对应十进制的数字是多少呢?是不是 255 呢?你可以先思考一下再看下面的内容~

2.2 符号位

对于的 11111111,如果它对应一个无符号变量,那么其表示十进制的数字255(即 2^8 -1=255)。但是对于存放signed类型的数据,左边第一位表示符号位。符号位为0,表示正整数;为1,表示负整数。一个8位的整型变量,除去左边第一位符号位,剩下表示值的只有7个比特位。

事实上计算机是用补码的形式来存放整数的值,其中正数的补码是该数的二进制形式,而负数的补码需要通过以下几步获得:

  • 先取得该数的绝对值的二进制形式,符号位置为1;
  • 符号位不变,将第1步的值按位取反(即将 0 都变为 1,1 都变为 0);
  • 符号位不变,最后将第2步的值加1。

如下图为正数 7 和负数 -7 的补码

一个字节的有符号数的取值范围如下图所示

其中我们可以看到负数最高可以到 -128,而正数最高只能到127,这是为什么呢?主要因为 0 也占据了整数中的一部分,所以导致正数最高只能到127。

那聪明的你现在一定知道将无符号整型赋值为-1,打印输出却是 65535 的原因了吧~如果知道的话可以留言回复哦~

2.3

基本数据类型的取值范围

基本数据类型的取值范围如下面的两张图所示,一张图主要是字符型和整数型,另一张图主要是小数型。

2.4 举例说明

下面是一个通过 “计算指数值” 的程序来说明取值范围这一概念,如下所示

在Ubuntu16.04下面使用 gcc 编译执行可以使用下面这条命令

gcc -lm tmp.c && ./a.out

其中的 lm 表示表式我们使用了<math.h> 这个头文件,&&省略了原本的 -o 的操作,此时生成的可执行文件名为 a.out,通过上面的语句进行编译执行得到如下的结果

可以看到 gcc 给出了 Warning 中指出了常量转换溢出(overflow),然后我们可以验证一下上面给出的结果是否正确。通过计算器可以知道 2^32 -1 的正确结果是 4294967295,与上面给出的结果不符。

出现这个的问题在于,在默认情况下 int 为有符号型,所以第一位是符号位,不能用来存放数字,所以如果我们将 32 位都拿来存放数字很容易溢出的现象。那如何进行修改呢?肯定不是修改一处啦,想好了也可以留言回复哦~

本文分享自微信公众号 - 轮子工厂(Programmer-ing),作者:轮子工厂CFO

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-10-09

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 有哪些实用且堪称神器的Chrome插件?吐血推荐!!!

    相信很多人都在使用 Chrome 浏览器,其流畅的浏览体验得到了不少用户的偏爱,但流畅只是一方面, Chrome 最大的优势还是其支持众多强大好用的扩展程序(E...

    谭庆波
  • 这真的是你了解的网络吗?

    无论是 C/S 开发还是 B/S 开发,无论是前端开发还是后台开发,网络总是无法避免的,数据如何传输,如何保证正确性和可靠性,如何提高传输效率,如何解决会话管理...

    谭庆波
  • 朋友圈长文不折叠神器

    前一段时间,微信朋友圈悄悄改版,当你发一段长文字的时候,就会被折叠成一行,需要点击进去才能看到详细内容,如下图示:

    谭庆波
  • Java中的基本数据类型转换(自动、强制、提升)

    Java技术栈
  • 第十九节:Java基本数据类型,循环结构与分支循环

    byte -> short,char -> int -> long float -> double long -> double int -> float

    达达前端
  • 05:素数回文数的个数

    05:素数回文数的个数 查看 提交 统计 提问 总时间限制: 1000ms 内存限制: 65536kB描述 求11到n之间(包括n),既是素数又是回文数的整数...

    attack
  • P3376 【模板】网络最大流(70)

    题目描述 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流。 输入输出格式 输入格式: 第一行包含四个正整数N、M、S、T,分别表示点的个数、有向边的个...

    attack
  • P3371 【模板】单源最短路径

    题目描述 如题,给出一个有向图,请输出从某一点出发到所有点的最短路径长度。 输入输出格式 输入格式: 第一行包含三个整数N、M、S,分别表示点的个数、有...

    attack
  • SpringMVC下获取验证码

    zcqshine
  • P1807 最长路_NOI导刊2010提高(07)

    题目描述 设G为有n个顶点的有向无环图,G中各顶点的编号为1到n,且当为G中的一条边时有i < j。设w(i,j)为边的长度,请设计算法,计算图G中<1,n>间...

    attack

扫码关注云+社区

领取腾讯云代金券