本文分享自华为云社区《从深入理解底层的角度学习C语言的基本数据类型-云社区-华为云》,作者:。
大家从学生时代就开始学习C语言的基本数据类型,但是有多少人尝试从低层次的角度去学习呢? 本文将采用问答的形式来慢慢分析相关内容和困惑。
数据类型数字和符号数据类型转换浮点数据类型数字和符号
问题:C 中的签名和类型有什么区别?
A:以char char和 char为例(因为都是1字节,所以更容易举例)
假设某个局部变量a在内存中存储为0xff(即二进制)
执行("%d", a)时,输出是255还是-1?
如果 a 未签名,则为 255。
如果 a 有符号,则为 -1。
问:为什么有符号 0xff 输出 -1?
答:这就是补码的概念。
正数的补码是它本身
负数的补码在原码的基础上,符号位不变,其余位取反,最后+1。 (即在补码的基础上+1)
原码、补码、+1、-1补码的表达式如下:
[+1] = []原=[]反=[]补
[-1] = []原=[]反=[]补
问:已知正数和负数默认为二进制补码形式。 为什么不能用原始码来表示数字呢?即只用第一个标识位,后面的7位代表真正的绝对值。
答:计算机CPU在进行计算时,无法区分符号位,只会硬性将8位数字相加。
假设做减法,则如下
1 - 1 = 1 + (-1) = [] 原 + [] 原 = [] 原 = -2
可见,符号位信息会误导减法的计算。
问:那为什么不使用反码呢?
A:因为补码有两种表示0的方式,可以表示-0,也可以表示+0,相当于浪费。
这种情况在补码中不存在。 代表-1,代表0。
问:为什么要有补码? 代码补码有什么好处?
A:计算机在执行1 - 1时,希望使用加法动作,而不希望进行if-else判断。 它在加减法之前使用符号位来判断正负,这对计算机的消耗很大。
利用补码机制,可以将1-1转化为1+(-1)
那么-1就是补码0xff,和0x01相加就变成0了,也就是不需要真正的减法。
问:我刚才提到CPU想要所有位加法但拒绝做减法。 为什么?
答:因为CPU的减法、乘法、除法都是基于加法、移位等运算。
加法过程依赖于CPU的ALU累加器。 累加器后面的电路是数字电路异或门和与门的组合。
问:为什么在补码表示中,范围是-128到127? 为什么补码比原码和补码多一位?
A:就是上面提到的0的问题。在原码中,都是代表0,在补码中,都是代表0,而在补码中,只有一个0的表示。
同时有一个补码,最后7位取反+1,相当于-128。
原码、反码、补码知识详解(这个作者是我找到的最详细、最清晰的)
问:CPU在计算时如何识别是无符号还是有符号?
A:CPU处理的寄存器和内存中的数字没有带符号的信息。 CPU在做加法和减法时,会同时对有符号数进行无符号数/溢出标志,并不专门对待有符号数和无符号数。
有符号和无符号的区别是一个只属于(中级)高级语言的概念。 它反映在机器语言中。 这是与运算及其结果相关的指令的差异,不会反映在CPU处理的数字本身中。
即CPU处理时统一采用加法处理,但是否需要补运算则取决于提供的运算指令。
问:C语言中的char是 char还是char?
一:
问:int有没有可能像char一样,即可能是int,也可能是int?
答:int 必须是有符号 int。 不同的编译器没有什么不同。
Q:为什么char可以区分有符号和无符号,而int只能默认为int?
A:我个人的理解取决于应用场景。 char不一定参与计算,而int大多数情况下是有符号计算,所以最好默认为int。
问:什么是 ILP32、LP64 和 LLP64?
答:指的是这个操作系统中的数据类型以及它们所代表的位数。
我的意思是棉绒
L代表龙
LL 表示长长
P 指向指针
32和64分别指32位和64位。
Q:为什么要用LLP64这么奇怪的模型? 在该模型中,long为32位,long long为64位。
A:知乎大师陈硕的回答:
我的猜测是,API 从 16 位升级到 32 位发生得太晚了 - 大约在 1995 年发布 95 的时候。
之前虽然也有NT 3.x和NT,但是看起来都比较小众。
Unix从16位到32位的升级发生在1980年左右。当时,VAX上运行的Unix/32V和3BSD都是32位的。
结果就是双方的程序对short/int/long长度的理解习惯不同:
Unix程序习惯int为32位,但long不一定只能是32位。 /DOS习惯了long是32位的,而int可能是16位也可能是32位,因为它刚刚从16位升级。
升级到64位的时候,如果升级long到64位,就会破坏很多原来程序的假设。
我必须使用一种新类型来表示 64 位整数。 不管怎样,在32位程序中,有64位整数,所以就用它吧。
详细数据类型显示:
PS:从上面可以看出,Java虚拟机的优点之一就是对于开发者来说,它屏蔽了不同系统条件下的数据位数。
Q:那么还有一个问题,Java虚拟机如何实现不同平台可以运行相同的Java代码而不用担心底层数据类型呢?
A:如图所示,类字节码都是相同的,但是不同的系统有不同的虚拟机解释器实现,并且解释器实现处理不同的数据类型数字。
数据类型转换
问:C 中隐式类型转换的规则是什么?
一:
问:以下示例的输出是什么?为什么?
一:
void Test()
{
int a = -1;
unsigned b = 10;
if (a > b)
{
printf("a is greater than b.\n");
}
else
{
printf("a is less than or equal b.\n");
}
}
>b 表示 a 大于
因为a=-1,所以存储的二进制是。 强制转换时,二进制文件不会改变,但向编译器表示的大小变为255。
浮点数
float、long的位数、有效位数及数值范围如下:
问题:下面的代码输出什么?
#include
int main(void)
{
float a = 9.87654321;
float b = 9.87654322;
if(a > b)
{
printf("a > b\n");
}
else if(a == b)
{
printf("a == b\n");
}
else
{
printf("a < b\n");
}
return 0;
}
A:输出“a=b”,因为float最多有7位有效小数。
问:对于32位浮点数,1位是符号位,23位是位数,8位是指数。 这三个除法如何获得浮点数的有效位数和数值范围呢?
答:标准理解。
【计算机组成原理】标准
有人问为什么要学这个?
对于高精度场景下的浮点计算,掌握标准很重要,否则无法理解高精度场景下计算过程中出现的各种问题。 特别是一些金融场景会对小数点后的数字特别敏感。
问:Java 类可以表示任意精度。 原理是什么?
答:原理很简单。 就是将小数扩大N倍,转换成整数,然后进行计算。 同时,结合指数,可以在不损失精度的情况下得到结果。
使用 long 和 scale 来存储精确值。
点击下方第一时间了解华为云新技术~
华为云博客_大数据博客_AI博客_云计算博客_开发者中心-华为云