1. 结构体中元素的地址
我们知道,结构体一般包括很多元素,结构体的大小为所有元素的大小总和(包括字节对齐)。
那么在结构体中,不同元素之间的地址相对位置是什么关系呢?
是先定义的元素地址在低地址还是后定义的元素地址在低地址呢?
我们通过一段代码来测试一下(我电脑型号为R9000P,AMD处理器,x86架构,win10操作系统,DevC++)
#include <stdio.h>
typedef struct {
int a;
int b;
}Test;
Test test1;
int main() {
Test test2;
printf("test1的a地址为%d,b地址为%d\n", &test1.a, &test1.b);
printf("test2的a地址为%d,b地址为%d\n", &test2.a, &test2.b);
return 0;
}
运行结构如下图所示
这边一起测试了一下全局变量和局部变量的情况。
test1为全局变量(存储在堆区),test2为局部变量(存储在栈区)。
可以看出都是先定义的元素在低地址,后定义的元素在高地址。
2. 大小端的概念(字节大小端、位的大小端)
举例说明字节大小端:
内存地址 | 0x00004000 | 0x00004001 | 0x00004002 | 0x00004003 |
---|---|---|---|---|
0X12 | 0x34 | 0x56 | 0X78 |
- 如果是大端处理器:这段数代表:0x12345678;
- 如果是小段处理器:这段数代表:0x78563412 ;
可以用代码测试一下本机的字节大小端
#include <stdio.h>
typedef union {
int a;
char b[4];
}Test;
int main() {
Test test1;
test1.a = 1;
printf("b数组的第四个元素的值为%d", test1.b[0]);
return 0;
}
运行结果如下图
我们知道对于数组,低索引的元素是位于低地址的,根据数组b的第一个元素为1可以看出,测试电脑是字节小端模式。
对于二进制数10011101B
- 如果在内存中的位置为(LSB)10111001(MSB),则为小端模式;
- 如果内存中的位置为(MSB)10011101(LSB),则为大端模式。
继续可以用代码测试一下位的大小端:
#include <stdio.h>
typedef union {
int a;
struct {
unsigned int d1:1;
unsigned int d:30;
unsigned int d2:1;
}bitField;
}Test;
int main() {
Test test1;
test1.a = 1;
printf("bitField的值d1为%d\n", test1.bitField.d1);
printf("bitField的值d2为%d", test1.bitField.d2);
return 0;
}
运行结果如下图:
通过运行结果可知,此系统的位的大小端为小端模式,d1代表最低位LSB。
再看一段代码
#include "stdio.h"
struct kk
{
unsigned a:2;
unsigned b:3;
unsigned c:2;
unsigned d:1;
}
kt;
int main()
{
char result =3;
memcpy(&kt,&result,1);
printf(" a = %d, b = %d, c = %d, d = %d,ok/n",kt.a,kt.b,kt.c,kt.d);
return 1;
}
在sun unix上用cc编译,结果为0,0,1,1
在2000上用VC6.0编译,结果为3,0,0,0
C语言的位域中,每个field是严格按照bit地址从低到高排列的:
==============
-低->->->高-
a b c d
==============
接下来看如何解析这个字节。
在little-endian机器上,result字节中各个比特的存放排列如下所示
==============
-低->->->高-
11000000
==============
对应到四个位域,得
a=3
b=0
c=0
d=0
在big-endian机器上,result字节中各个比特的存放排列如下所示
==============
-低->->->高-
00000011
==============
对应到四个位域,得
a=0
b=0
c=1
d=1
总结:
-
C语言的位域类型使用时,各个field的摆放是按从低到高的bit顺序排列的。
-
把数据的存放和解析分开,就可以很容易解释字节序的问题。