计算机字长是 计算机字长是什么选择题
计算机领域中的几个基础概念,比如数制、码制、位、字节、字长以及内存对齐,都是相互关联的。掌握这些概念不仅对理解计算机的内部运作至关重要,还能帮助我们更有效地编写程序和优化性能。
数制的基本概念:符号数与模数
在日常生活中,我们最常使用的数制是十进制。时间的计量使用的是60进制,月份则采用12进制。对于计算机而言,主要使用的是二进制,同时辅以16进制和8进制。16进制和8进制均与2的幂次方有关:3个二进制位可以表示一个8进制位,而4个二进制位则对应一个16进制位。
对于任意进制n,其规则如下:
符号的数量为n-1;
用两位数字表示n进制的n,即用10来表示n进制的n。n进制的模数特性是,当某个数m进行模运算时,结果总会小于n,比如m % n的结果必然小于n。
计算机选择二进制作为主要数制是因为其逻辑电路最容易实现,且具备出色的稳定性。布尔代数和香农在开关电路中的应用为此奠定了理论基础。0和1可以通过继电器、晶体管的开关状态或电容中的电信号有无来表示,门电路如与门、或门、非门等则用于实现布尔代数中的逻辑运算。
那么,从数字组合的角度来看,哪种进制效率更高呢?让我们首先考虑一个问题:
如果a * b = N,那么a取什么值时,a^b的值会最大?(a和b可以是小数)
假设f(x) = x^(K/x),其中x > 0,K是一个大于0的常数。对f进行求导,发现x = e时,f(x)取到极大值,而e的值约为2.71828……。与e最接近的整数并非2,而是3。
在计算机中,一个32位的系统可以用32个二进制位来表示,即64个元素,能够表示2^32 ≈ 4.29 * 10^9个不同的数字。假设用三进制表示,这64个元素可以表达3^21.3 ≈ 1.45 * 10^10个精度,而即使是3^21,也能表示约1.05 * 10^10个精度。这表明,三进制的组合数要比二进制多。四进制的组合数则会有所减少(实际上,e进制具有最大的组合数)。三进制硬件实现复杂,而二进制硬件实现简单且稳定,因此二进制被认为是计算机的最佳数制,就如黄金是最自然的货币一样。
前苏联曾尝试过三进制计算机:在这种系统中,逻辑状态并非仅限于真或假,还包括未知。三进制逻辑学中,符号1代表真,-1代表假,0代表未知。三进制逻辑电路的电压有三种状态:正电压(1)、零电压(0)和负电压(-1)。
码制:信息的编码方式
通过不同符号的组合规则,我们可以表示各种复杂的信息,例如摩斯密码、电码、以及英文和中文的字符。在计算机底层,无论是数据还是指令,都是以二进制的0和1来表示的,硬件则通过晶体管的开关或电容中的电信号来实现这些二进制状态。
编码的形式包括:正整数的原码、负整数的补码、浮点数的IEEE754码制(包括阶码的移码);字符编码如ASCII码、UTF-8的Unicode码、GBK码等,使用不同长度的二进制位来表示字符;位图编码涉及图像像素的数字化;声音编码涉及声波振幅和频率的采样数字化。
数位:组合与硬件实现
二进制位的基本实现是通过晶体管或电容的开关来完成的。每一个二进制位所包含的信息量被称为比特。
从简单的门电路到复杂的集成电路,关键在于组合的复杂性。计算机中,8个位组合成一个字节,这不仅是基本的寻址单位,也是位运算的基础。
字节:存储和寻址的基本单位
在计算机中,8个位组合成一个字节,这个字节是基本的寻址和运算单位。不同的数据类型需要不同长度的内存单元。例如,在ASCII码中,一个字节可以表示一个字符,而不同的字符集(如宽字符集、多字符集)可能需要不同数量的字节来表示。
字长:批量处理的位数
现代计算机内部实现通常是串行操作的,但通过快速切换的串行方式模拟人类感知的并行处理。为了提高效率,计算机可以一次性访问多个字节,例如32位系统一次访问32个位,即4个字节,64位系统则一次访问8个字节。
字长指的是计算机一次性处理的比特位数。计算机的寄存器、处理的典型数值(如int)、CPU和内存之间的数据传送单位通常都是以字长为单位的。现代计算机的字长通常为32位或64位。内部数据的表示或处理也通常是以字长为基准的。
内存对齐:提高数据操作效率
由于计算机按字长处理数据,对于复合数据类型(如结构体、类、共用体),内存对齐是提高数据操作效率的关键。每个平台上的编译器都有其默认的“对齐系数”(也称为对齐模数)。例如,在32位Windows平台下,VC默认的对齐系数为8(可以通过VC->Project->settings->C/C++->Code Generation中的struct member alignment值进行设置)。程序员也可以通过预编译指令#pragma pack(n)来调整对齐系数,其中n的值可以是1、2、4、8或16。
内存对齐规则包括:
1、
数据成员对齐规则
:对于结构体(struct)、联合体(union)或类(class)的数据成员,第一个成员放在偏移量为0的位置,之后每个成员的对齐按照#pragma pack(n)指定的数值和成员自身长度中较小的那个进行。
成员对齐系数 = min(数据成员类型, n)
2、
整体对齐规则
:在所有数据成员对齐完成后,结构体(或联合体)本身也需要进行对齐。对齐的依据是#pragma pack指定的数值和结构体最大数据成员长度中的较小者。
整体对齐系数 = min(最大数据成员长度, 8)
3、结合1和2的规则:当#pragma pack的n值等于或超过所有数据成员长度时,该n值的大小不会产生任何效果。
如果未通过#pragma pack(m)指定数值,
VC规定各成员变量存放的起始地址相对于结构的起始地址的偏移量必须是该变量类型所占字节数的倍数
以下是常见类型的对齐方式(以VC6.0、32位系统为例):
类型 对齐方式(变量存放的起始地址相对于结构的起始地址的偏移量)
Char 偏移量必须为sizeof(char)即1的倍数
Short 偏移量必须为sizeof(short)即2的倍数
int 偏移量必须为sizeof(int)即4的倍数
float 偏移量必须为sizeof(float)即4的倍数
double 偏移量必须为sizeof(double)即8的倍数
根据以上对齐方式,各成员变量会按照在结构体中出现的顺序申请空间,并调整位置。VC编译器会自动填充必要的字节以确保结构体的总大小为最大对齐边界数的整数倍。例如,结构体的总大小会
在结构体中,VC编译器会在为最后一个成员变量分配空间后,根据需要添加填充字节以确保结构体的总大小为最大对齐边界数的整数倍,即结构体的大小通常是最大对齐类型的倍数。以下是几个示例:
例1:
考虑结构体Node1的内存分配,VC会依照成员变量的顺序和对齐方式进行以下分配:
1. 为第一个成员m1分配空间,起始地址为结构体的起始地址(偏移量0),占用8个字节(sizeof(double))。
2. 第二个成员m2的偏移量为8,满足sizeof(char)的倍数,因此m2放置在偏移量8的位置,占用1个字节(sizeof(char))。
3. 第三个成员m3的偏移量为9,为了满足sizeof(int)=4的倍数,VC会在偏移量9处填充3个字节以对齐。接下来,m3放置在偏移量12的位置,占用4个字节(sizeof(int))。
4. 结构体总大小为16,刚好是sizeof(double)的倍数。结构体Node1的总大小为16。
例2:
分析结构体Node2:
1. 成员a占用1个字节,因此a放在了偏移量1的位置。
2. 第二个变量b占用4个字节。为了保证偏移量为4的倍数,b的偏移量在a之后填充了3个字节,使b放在偏移量5的位置。
3. 成员c放置在偏移量9的位置,9的下一个地址是sizeof(int)=4的倍数,因此也符合对齐规则。
4. 结构体总大小为12,因为偏移量加上最后一个成员的大小(9+4=13)不符合4的倍数,所以需要填充3个字节。结构体Node2的总大小为12。
例3:
计算结构体Node3的大小:
1. 成员变量a的偏移量为0;
2. 结构体Node3的整体偏移量为8,符合4的倍数,因此总大小为8。
3. 结构体的总大小也需要为8,因为最后一个成员的偏移量加上其大小为8。结构体Node3的总大小为8。
例4:
计算结构体n3的大小:
1. 成员c1的偏移量为0;
2. n3的偏移量为4,符合4的倍数,结构体n3的大小计算为8。
3. 对于c2,其偏移量为12,符合4的倍数,但13的大小不能被4整除,因此在结构体末尾补充3个字节。
4. 结构体n3的总大小为16。
结构体的大小等于最后一个成员的偏移量加上其大小,再加上末尾的填充字节数。公式为:
sizeof( struct ) = offsetof( last item ) + sizeof( last item ) + sizeof( trailing padding )
这种内存对齐方式保证了数据存取的高效性,使得计算机在处理数据时能减少不必要的内存访问开销,从而提升性能。了解并掌握这些内存管理的细节,对于编写高效程序和优化系统性能具有重要意义。