内存模型是C/C++数据抽象的基础,是C/C++最底层的语言设施。不过,C与C++关于内存模型的表述方式是不同的。C++明确提出了内存模型的概念,但C没有这样做,而是对内存模型的构件例如bit和byte单独定义。尽管形式不同,但两者关于内存模型的语义是基本相同的,都由bit构成byte,bit是构成对象的最小单位,而可寻址的最小数据存储单位是byte,这意味着位域(bit-field)可以构成最小的对象,但不能使用取址运算符,例如下面代码:
byte内的bit是连续排列的,byte内的空间不存在类似字节对齐那样的填充物,即使一些在逻辑上将某些位视作填充物的场合,在byte看来仍然是正常的bit。例如:
位域a和b之间有一个匿名位域,通常用于使下一个位域按某种方式对齐,以利于提高执行效率,在逻辑上这个匿名位域就是一个填充物,但从内存模型的角度看它依然是一个正常的位域对象。
二、字节的长度
一个byte应该有多少bit?很多人会冲口而出:8bit。当然,多数人所熟悉的环境的byte的确是8bit的,但是,如果据此以为C/C++所支持的所有系统的byte都是8位的,就大错特错了!事实上,C/C++标准支持某些一个byte超过8位的系统,C标准在其rational中解释了这个问题:
3. Terms and definitions
• All objects in C must be representable as a contiguous sequence of bytes, each of which is at least 8 bits wide.
• A charwhether signed or unsigned, occupies exactly one byte.
(Thus, for instance, on a machine with 36-bit words, a byte can be defined to consist of 9, 12, 18, or 36 bits, these numbers being all the exact divisors of 36 which are not less than 8.) These strictures codify the widespread presumption that any object can be treated as an array of characters, the size of which is given by the sizeof operator with that object’s type as its operand.
有些字长36位的执行环境每个byte的构成可能是9、12、18和36位,都是不小于8的36的因数。因此,C/C++规定一个byte的二进制宽度是实现相关(implementation defined)的,至少由8bit构成,而非必定8位。
为什么至少8位?C/C++规定,byte的二进制宽度必须能够表示基本执行字符集的所有字符,而基本执行字符集共有100个字符,需要7位二进制宽度,再加上C/C++数值表示的二进制编码方式所需要的1个符号位,因此至少需要8位。
C在limits.h(C++则为climits)头文件中使用了一个宏CHAR_BIT,用于指示当前编译环境的byte的二进制宽度。一段高移植性的代码不应该基于一个byte为8bit的假设。例如下面一段在面试中经常遇到的代码:
这段代码会有什么结果?死循环通常是自以为是的出题者所认为的正确答案,但这个答案只正确了一半。这段代码存在两类不良设计:一是基于8位byte的假设;二是使用了255这个魔数,没有进行局部化。在byte超过8位的环境中,上述代码就不一定是死循环了。保证在任何符合标准的环境中都是死循环的改进是如下这样的: