您的位置  > 互联网

从深入理解底层的角度学习C语言之基本数据类型

本文分享自华为云社区《从深入理解底层的角度学习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博客_云计算博客_开发者中心-华为云