零散知识点

4/18/2022

# int占几位?

最近在看深入理解计算机系统这本书,上面提到了在32位机器和64机器中int类型都占用4个字节。
后来,查了The C Programming language这本书,里面有一句话是这样的:Each compiler is free to choose appropriate sizes for its own hardware, subject only to the restriction that shorts and ints are at least 16bits, longs are at least 32bits, and short is no longer than int, which is no longer than long.

意思大致是编译器可以根据自身硬件来选择合适的大小,但是需要满足约束:short和int型至少为16位,long型至少为32位,并且short型长度不能超过int型,而int型不能超过long型。

这即是说各个类型的变量长度是由编译器来决定的,而当前主流的编译器中一般是32位机器和64位机器中int型都是4个字节(例如,GCC)。
下面列举在GCC编译器下32位机器和64位机器各个类型变量所占字节数:

C类型 32bit 64bit
char 1 1
short int 2 2
int 4 4
long int 4 8
long long int 8 8
char* 4 8
float 4 4
double 8 8

需要说明一下的是指针类型存储的是所指向变量的地址,所以32位机器只需要32bit,而64位机器需要64bit。
经过询问,网上查找以及测试,发现 数据类型占内存的位数实际上与操作系统的位数和编译器(不同编译器支持的位数可能有所不同)都有关 ,具体某种数据类型占字节数得编译器根据操作系统位数两者之间进行协调好后分配内存大小。 在使用的时候如想知道具体占内存的位数通过sizeof(int)可以得到准确的答案
稍微整理一下64位常用的,微软这里 (opens new window)很全

数据类型 字节 取值范围
char 1 -128~127
usigned char 1 0~255(2^9-1=255)
short 2 -32768~32767
usigned short 2 0~65535(2^17-1=65535)
int 4 -2147483648~2147483647
unsigned int 4 0~4294967295(2^33-1=4294967295)
long 4 -2147483648~2147483647
usigned long 4 0~4294967295
long long 8 -9223372036854775808~
9223372036854775807
usigned long long 8 0~18,446,744,073,709,551,615
float 4 1.17549 *10^-38~ 3.40282*10^38
double 8 2.22507 *10^-308~1.79769*10^308
long double 12 2.22507 *10^-308~1.79769*10^308

n位无符号数分配的时候 min全0=0~max全1=(2^n+1)-1
n位有符号数分配的时候,min -全1=-(2^n-1)-1~max +全1=(2^n-1)
考虑一下空间的分配,分三部分 先拿出一个符号位,n位这时候bit少了一位n-1 即 min -全1=-(2^n-1)~max +全1=(2^n-1) 注意此时0处正0仍然为0(0000),没有负0(1000),负0的空间实际上被分配给了负数,-全1时正好可以表示多一位-(2^n-1)+1
但是这样负数的表示非常奇怪,往后移了一位
计算机是用补码存储有符号数据的,其中正数的补码是该数的二进制形式,而负数的补码需要通过以下几步获得:

  1. 先取绝对值的二进制形式,符号位置为1;
  2. 符号位不变,按位取反;
  3. 最后将获得值加1。

这时候再回来看怎么分配的,-1 的补码是 11111111,这个数据正好对应着无符号数中的 65535,这样-1就占据了-0,-65535占据了-1的空间,-2开始就正常了。

# 探究Byte的定义

再探究一下Byte的定义:能够编码一个字符的最小可寻址单元:

Historically, the byte was the number of bits used to encode a single character (opens new window) of text in a computer 1 (opens new window)
2 (opens new window) and for this reason it is the smallest addressable (opens new window) unit of memory (opens new window) in any computer architectures (opens new window).
https://en.wikipedia.org/wiki/Byte (opens new window)

其实以前也有过4位,6位或7位为一byte的标准,IBM 701(36位字长,18位byte)、IBM 702 (opens new window)(7位字长,7位byte)、CDC 6600 (opens new window)(60位字长,12位byte)等等。但是我觉得,考虑到包含的信息量不够大(所以4位被弃用了),还有不够整齐美观(即不方便扩展,不适合整齐划一进行工业生产;想象一下假如以7位为一byte,内存和硬盘的大小就不再是2^n bit大小了,而是2^(n-1)*7 bit大小了,有些别扭),所以只有8位作为最通行的标准流行开来。

8位一Byte,字长为2^n bits,这个标准来自于IBM system/360(1950年代到1960年代)。IBM也参与了ASCII码(7位128个字符)的制定(1963),但是同时开展了EBCDIC表(8位256个字符)的制定,作为自己公司的BCDIC标准的一个升级版本,其实就是想与ASCII竞争,但这个表的确很乱,而且版本也不统一,造成了很多吐槽(比如字母表居然不连续,加入了很多用不到的字符等等)这个标准非常坑爹,但是却推广了8 bit为一字节的概念通行开来。

接下来AT&T(American Telephone and Telegraph Company)公司和8位处理器的兴起进一步推广了8位作为一个byte这一事实标准。由于ASCII码只有7位,出于表达英语字母及其他符号的必要,各个国家开始探索如何用多余的一位来表示其他的字符,这样就出现了很多“扩展ASCII字符集”,但是标准不一。IBM也推出了一个,叫做Code page 437 (opens new window)。这个表也是MS-DOS所用的扩展ASCII码集,但是并不是最后的唯一标准。直到1985年,是国际标准化组织 (opens new window) (ISO)及国际电工委员会 (opens new window)(IEC)才联合制定的一系列8 (opens new window)字符集的标准,称为ISO 8859,全称ISO/IEC 8859,这才统一了混乱的标准。

说了这么多,只想表明一点:一个字节之所以有8个bit,是历史原因造成的(计算机前身是打印机),但是也是计算机原理,尤其是二进制特性的必然结果,是数据存储需要(必须要能在一个字节内表示超过100种状态,包括常用数字,大小写字母,和打印机上的其他控制符号)和早期计算机存储价格昂贵(所以没有用10个,16个或更多位),加上商业利益追求(IBM的推广)共同作用的结果。

# char 的长度

在Linux C编程中使用Unicode和UTF-8 (opens new window) 但是在printf里直接打印中文字符串就可以

# EPSILON的含义

有时候计算机判断(1.0 == 10.0 / 10.0)的时候,并不总是返回true。因为浮点数计算可能会产生一定点误差,而这误差是无法避免的。正确的做法是判断两个值是否在这个误差范围内,而误差范围就是从正FLT_EPSILON 到负FLT_EPSILON 内。(1.0 > (10.0 / 10.0) - FLT_EPSILON && 1.0 < (10.0 / 10.0) + FLT_EPSILON)。双精度为DBL_EPSILON

FLT_EPSILON 在 float.h 头文件 宏定义如下

后面的注释可以理解为 这个数是 能使 (1.0 + FLT_EPSILON != 0) 成立的最小的数 也就是说 小于FLT_EPSILON 的数 加上 1.0 都等于 1.0 https://blog.csdn.net/l773575310/article/details/52791392 (opens new window)  //TODO

The Most Expensive One-byte Mistake - ACM Queue (opens new window) 最贵的1Byte错误我