对于跨越多字节的程序对象,我们需要建立两个规则:1)这个对象的地址是什么;2)在内存中如何排列这些字节。
在几乎所有的机器中,多字节对象都被存储为连续的字节序列,对象的地址为所用字节中最小的地址。
排列对象的中字节有两个通用规则:小端法(little endian)和大端法(big endian)。
小端法即最低有效字节在最前面(低地址);大端法正好相反。
That is, in a big endian system, the most significant bit is stored at the lowest bit address and in a little endian system, the least significant bit is stored at the lowest bit address。
#include <stdio.h> union Test { unsigned char ucArr[4]; unsigned int uiVal; }; void TestEndian() { union Test flag; flag.uiVal = 0x12345678; if (flag.ucArr[0] == 0x12) { printf("big endian\n"); } else { // flag.ucArr[0] == 0x78 printf("little endian\n"); } } int main() { TestEndian(); getchar(); return 0; }
2、位序
位字段(bit-field),或简称字段,是“字”中相邻位的集合。“字”(word)是单个的存储单元,它同具体的实现有关。字段的所有属性几乎都同具体的实现有关。字段是否能覆盖自边界由具体的实现定义。字段可以不命名,无名字段(只有一个冒号和宽度)起填充作用。特殊宽度0可以用来强制在下一个字边界上对齐(长度为0的位域是给编译器的一个信号,告诉编译器将下一个位域在一个存储单元的起始位置对齐)。某些机器上字段的分配是从字的左端至右端进行的,而某些机器上则相反(移植需要考虑这方面的问题)。字段不是数组,并且没有地址,因此对它们不能使用&运算符。
位域字节序必须注意:不论大端序或小端序CPU,多字节位域都是从存储器的低字节开始存储;在小端序CPU中,在一个字节中,从低位开始存储;在大端序CPU中,在一个字节中,从高位开始存储。
union test { unsigned char ucVal; struct ucst { unsigned char a : 1; unsigned char b : 4; unsigned char c : 3; } stVal; } unflag; int main() { // 1 1010 010 unflag.stVal.a = 1; // 1 unflag.stVal.b = 5; // 0101 unflag.stVal.c = 2; // 010 for (int i = 0; i < 8; i++) { printf("%d", unflag.ucVal >> i & 0x01); } printf("\n"); getchar(); return 0; }
大小端中位序的情况
#include <stdio.h> // opaque and show #define YES 1 #define NO 0 // line styles #define SOLID 1 #define DOTTED 2 #define DASHED 3 // primary colors #define BLUE 4 /* 100 */ #define GREEN 2 /* 010 */ #define RED 1 /* 001 */ // mixed colors #define BLACK 0 /* 000 */ #define YELLOW (RED | GREEN) /* 011 */ #define MAGENTA (RED | BLUE) /* 101 */ #define CYAN (GREEN | BLUE) /* 110 */ #define WHITE (RED | GREEN | BLUE) /* 111 */ const char * colors[8] = {"Black", "Red", "Green", "Yellow", "Blue", "Magenta", "Cyan", "White"}; // bit field box properties struct box_props { unsigned int opaque : 1; unsigned int fill_color : 3; unsigned int : 4; // fill to 8 bits unsigned int show_border : 1; unsigned int border_color : 3; unsigned int border_style : 2; unsigned char : 0; // fill to nearest byte (16 bits) unsigned char width : 4, // Split a byte into 2 fields of 4 bits height : 4; }; /* Each prepocessor directive defines a single bit */ #define KEY_UP (1 << 0) /* 000001 */ #define KEY_RIGHT (1 << 1) /* 000010 */ #define KEY_DOWN (1 << 2) /* 000100 */ #define KEY_LEFT (1 << 3) /* 001000 */ #define KEY_BUTTON1 (1 << 4) /* 010000 */ #define KEY_BUTTON2 (1 << 5) /* 100000 */ int gameControllerStatus = 0; /* Sets the gameControllerStatus using OR */ void keyPressed(int key) { gameControllerStatus |= key; } /* Turns the key in gameControllerStatus off using AND and ~ (binary NOT)*/ void keyReleased(int key) { gameControllerStatus &= ~key; } /* Tests whether a bit is set using AND */ int isPressed(int key) { return gameControllerStatus & key; } 参考说明:部分内容来自《CSAPP》及维基百科
https://en.wikipedia.org/wiki/Bit_field