当前位置: 首页 > news >正文

深入理解计算机操作系统(三)

阅读经典——《深入理解计算机系统》02

  1. 基本数据类型
  2. 大小端模式
  3. 整型数范围与C标准
  4. 复合型类型转换——从short到unsigned

<h3 id="what_is_information">基本数据类型</h3>

让我们复习一下C语言中基本数据类型的字节数

名称32位64位
char11
short int22
int44
long int48
long long int88
char *48
float44
double88

这其实是很基础的知识,但是值得一提的是,表中只有两个数据类型在32位和64位计算机中使用了不同的字节数,一个是long int,另一个是char *。其实不只是char *,任何数据类型的指针使用的字节数都和char *是一样的,所以这里更好的写法应该是type *

为了尽量使程序可移植,要小心从32位到64位的变化。例如,在32位机器中使用int保存变量的地址可行,但同样的程序移植到64位机器中就成了bug。所以不如尝试用long int保存变量的地址。这个时候,上面的表格就体现出了它的价值。

大小端模式

对于多于一个字节的数据类型,在内存中有两种存储方式,以整形数0x01234567为例

 
大小端模式

大端模式将高位存放在低地址,而小端模式将高位存放在高地址。这对我们编程有什么影响呢?说实话,在我写过的程序中并没考虑过大小端模式,但在如下几个方面,可以体现出大小端模式的影响:

  • 大端机器与小端机器间的网络通信。很明显,如果双方都遵循先发低位再发高位的规则,发送前后数据在内存中的存储方式是完全一致的,但大端机器和小端机器对同样的数据存储方式却会解析出完全不同的结果,因此数据出现差错。因此,解决办法是发送前全部转换成大端模式,对方接收后,再根据自己的机器类型转换成大端或小端模式。实际中网络通信的的确是这样做的。这部分的详细讲解将会出现在第11章。

  • 反汇编可以看到真实数据顺序。

    add %eax, 0x8049464

    反汇编结果为

    80483bd: 01 05 64 94 04 08

    操作数0x8049464被转换成了小端模式下的结果64 94 04 08。

  • 绕开类型系统的强制转换。例如如下代码可以测试出机器是大端模式还是小端模式:

int value = 0x01234567;
char *ch = (char *)(&value); if (*ch == 0x01) { //大端模式 } else if (*ch == 0x67) { //小端模式 } else { //其它 } 

由于ch一定指向value最低地址的字节,因此可以通过ch来判断系统的大小端类型。

整型数范围与C标准

本文最开始就给出了各个基本数据类型的字节数,根据字节数我们可以推断出在采用二进制补码编码的情况下各个类型的表示范围。比如说int的范围为-2,147,483,648 ~ 2,147,483,647。但是C标准的存在却提醒我们事实并非总是如此。

C标准规定的各类型整型数的范围与其典型值有所不同,通常小于其典型值范围,并且所有有符号类型只要求对称范围。例如,int只要求-32767 ~ 32767。虽然我们使用的编译器会按照系统位数来决定int类型的实际范围,但是,如果想要使代码能够跨平台,最好按照C标准规定的范围来设计自己的程序,这样只要编译器遵循C标准,代码就一定不会出错。否则,像int i = 99999;这样的语句,放到16位计算机上就直接溢出了。

接下来提一个有趣的事情,在32位计算机的头文件<limits.h>中,定义了各个基本数据类型的范围,以整型为例

#define INT_MAX 2147483647
#define INT_MIN (-INT_MAX-1) 

为什么最小值不直接写#define INT_MIN -2147483648呢?

因为对编译器来说,-2147483648是一个表达式,它的意思是对2147483648取负。但是2147483648这个数已经超出了整型数所能表示的范围,因此这样写是没有意义的。更详细的解释可以查看后面的参考资料。

复合型类型转换——从short到unsigned

数据类型既有不同的范围,又有不同的符号性质,当两者同时转换时,就需要多加注意。

例如,从short转换到unsigned需要分两步,实际过程相当于(unsigned)(int),而不是(unsigned)(unsigned short)。也就是说,先扩大范围,再改变符号性质。对于下面的代码

short s = -12345;
unsigned u = s;
printf("%u\n", u); unsigned u1 = (unsigned)(int) s; printf("%u\n", u1); unsigned u2 = (unsigned)(unsigned short) s; printf("%u\n", u2); 

打印结果uu1都是4294954951,而u253191

参考资料

  • 详解大端模式和小端模式 ce123
  • ANSI C, Standard C与GCC 思学
  • INT_MIN Jibz

文中若有错误或不当之处,恳请各位读者指出。
关注作者或文集《深入理解计算机系统》,第一时间获取最新发布文章。



作者:金戈大王
链接:https://www.jianshu.com/p/991c98493c1f
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

转载于:https://www.cnblogs.com/zzdbullet/p/9354574.html

相关文章:

  • GrapeCity Demo示例展示:如何用Spread.Sheets来创建应用|附演示文件下载
  • Glovo完成1.15亿欧元C轮融资,成为欧洲相关技术聚合中心
  • json提取嵌套数据
  • abstract 为什么不能与private,static,final一起使用????
  • springboot2整合OAuth2.0认证实例
  • 关于Vue和React区别的一些笔记
  • [Sdoi2010]地精部落
  • samba服务
  • RabbitMQ中各种消息类型如何处理?
  • 初识 JSP---(servlet / ServletConfig接口 / ServletContext接口)
  • 根据IP查地理位置信息
  • 使用git将代码推到coding
  • 理解在java “”i=i++;”所发生的事情
  • HDU 6342 Expression in Memories(模拟)多校题解
  • eclipse 更换国内镜像
  • [rust! #004] [译] Rust 的内置 Traits, 使用场景, 方式, 和原因
  • ABAP的include关键字,Java的import, C的include和C4C ABSL 的import比较
  • android高仿小视频、应用锁、3种存储库、QQ小红点动画、仿支付宝图表等源码...
  • Angular js 常用指令ng-if、ng-class、ng-option、ng-value、ng-click是如何使用的?
  • AngularJS指令开发(1)——参数详解
  • CSS进阶篇--用CSS开启硬件加速来提高网站性能
  • css选择器
  • ES6核心特性
  • Git同步原始仓库到Fork仓库中
  • Iterator 和 for...of 循环
  • Just for fun——迅速写完快速排序
  • MySQL数据库运维之数据恢复
  • PAT A1017 优先队列
  • QQ浏览器x5内核的兼容性问题
  • RxJS 实现摩斯密码(Morse) 【内附脑图】
  • storm drpc实例
  • Vultr 教程目录
  • 等保2.0 | 几维安全发布等保检测、等保加固专版 加速企业等保合规
  • 对超线程几个不同角度的解释
  • 构造函数(constructor)与原型链(prototype)关系
  • 关于springcloud Gateway中的限流
  • 老板让我十分钟上手nx-admin
  • 数据可视化之 Sankey 桑基图的实现
  • 听说你叫Java(二)–Servlet请求
  • 异常机制详解
  • 怎样选择前端框架
  • Nginx实现动静分离
  • 树莓派用上kodexplorer也能玩成私有网盘
  • # centos7下FFmpeg环境部署记录
  • # 数论-逆元
  • #FPGA(基础知识)
  • $.type 怎么精确判断对象类型的 --(源码学习2)
  • (读书笔记)Javascript高级程序设计---ECMAScript基础
  • (亲测)设​置​m​y​e​c​l​i​p​s​e​打​开​默​认​工​作​空​间...
  • (四)docker:为mysql和java jar运行环境创建同一网络,容器互联
  • (算法二)滑动窗口
  • (五)Python 垃圾回收机制
  • (一)u-boot-nand.bin的下载
  • (原創) 人會胖會瘦,都是自我要求的結果 (日記)
  • (转)德国人的记事本