对C语言整数类型的一点理解

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。

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

时间: 2024-10-12 07:16:21

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

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

其他整数类型 初学C语言时,int类型会满足你对整数的大多数需求. C语言还提供了三个关键字用以修饰基本的整数类型:short.long和unsigned.有以下几个注意点: (1)C语言没有具体规定各类数据所占内存的字节数,只要求long型数据长于或等于int型,short型数据短于或等于long型.因而short int类型可能占用比int类型更少的存储空间.用于仅需小数值的场合以节省空间.同int类型一样,short类型是一种有符号类型. (2)long int类型可能占用比int类型更多

网易云课堂_C语言程序设计进阶_第一周:数据类型:整数类型、浮点类型、枚举类型

C语言程序设计进阶_第一周:数据类型:整数类型.浮点类型.枚举类型 1.0数据类型 1.1整数类型 1.2浮点类型 1.3逻辑类型 1.4类型转换和条件运算 1.0数据类型 1 整数 char(%c), short, int(%d), long(%ld), long long(C99) 2 浮点数 float(%f), double(%lf), long double(C99) 3 逻辑 bool(C99) 4 指针 5 自定义类型 所表达的数的范围:char<short<int<flo

C语言的数据类型——整数类型和浮点类型

??基本数据类型分为整数类型和浮点类型两大类.其中,整数类型又可以被细分成有符号整型与无符号整型. 1.整数类型 有符号整型 short int int long int long long int char(使用整数存储字符) 无符号整型 unsigned short int unsigned int unsigned long int unsigned long long int unsigned char(使用整数存储字符) ??其中,后面的类型不能小于前面的类型,即short int占用

Swift 语言附注 类型

本页包含内容: 类型注解(Type Annotation) 类型标识符(Type Identifier) 元组类型(Tuple Type) 函数类型(Function Type) 数组类型(Array Type) 可选类型(Optional Type) 隐式解析可选类型(Implicitly Unwrapped Optional Type) 协议合成类型(Protocol Composition Type) 元类型(Metatype Type) 类型继承子句(Type Inheritance C

[转载] 对函数式编程的一点理解

原文: https://github.com/nixzhu/dev-blog/blob/master/2015-07-30-functional-programming.md 对函数式编程的一点理解 虽然有不少对“函数式编程”的解释,但我没有遇到让我满意的.我不是说解释要多么的具体.全面,或者让我立马会使用.变得很厉害,我就想知道它是怎么一回事儿. 作者:@nixzhu 先考虑一个过程.假设您性别男,爱好女.有位优雅的女士愿意与您做爱,不过这位女士对做爱有些要求:前戏至少要15分钟,性交要求在3

【C语言学习】指针再理解(一)

★内存和地址 内存的基本单位是字节,那么内存就可以按字节进行编址,就是给组成内存的所有连续的字节安排地址.其中一个最恰当的比喻就是房子与门牌号,假设有20间连续的房子,从最左边(或者左右边)开始分配门牌号1~20,给内存中字节分配的地址就相当于门牌号,字节就相当于房间.字节的容量只能存储一个字符.那么,内存是如何存储比字符更大的数据呢,比如:整型数据.浮点型数据? ★更大的内存单元 为了存储更大的数据,就会把两个字节或者跟多的字节合在一起组成更大的内存单元.比如内存可以以"字"为单位来

关于web开发的一点理解

对于web开发上的一点理解 1 宏观上的一点理解 网页从请求第地址 到获得页面的过程:从客户端(浏览器)通过地址 从soket把请求报文封装发往服务端   服务端通过解析报文并处理报文最后把处理的结果 封装成响应报文 发送给客户端(浏览器)  ,客户端解析响应报文  把正文(html css  javascript)渲染成我们见到的页面. 这就是我们如何看到页面的过程 图解 2对于网页的开发的框架的一点理解 上面提到了网页处理的过程  中 服务端解析请求报文 处理请求报文的过程 就是网站开发的框

C语言-浮点类型

C语言-浮点类型 浮点类型 在0的两侧有一小块区域,这个区域非常接近0,但是不等于0,是float(表达范围数量级10^-38^)或者double(达范围数量级10^-308^)无法表达的,而0是可以表达的:nan:不是一个有效的数字.有效数字:在有效数字范围是精确的,超出这个范围是不准确的. %e:输出科学计数法的形式,%E只是表示时字母大写. 在使用科学计数法时,数字与E或者e之间不要有任何空格.小数点位数较多时,double有时显示不出来小数位的数字如1E-10,以double输出时只是0

跟王老师学MySQL:MySQL数据类型之整数类型

跟王老师学MySQL:MySQL数据类型之整数类型 主讲教师:王少华   QQ群号:483773664 MySQL的数据类型包括整数类型.浮点数类型.定点数类型.日期和时间类型.字符串类型和二进制数据类型. 学习目标 整型包括哪些类型以及它们的取值范围 以tinyint为例,讲解了定义整型的三个属性 一.简介 整数类型是数据库中最基本的数据类型. 标准SQL中支持INTEGER和SMALLINT这两类整数类型. MySQL数据库除了支持这两种类型以外,还扩展支持了TINYINT.MEDIUMIN