引言
C语言的精粹是程序要可以随意操纵自己程序空间的任意内存,从这方面来说,C语言编程算是面向机器的编程。那么,熟悉C的数据如何存储就是显得很重要了。本篇内容就是记录自己探索C语言的数据结构在内存如何存储的过程。
结论只在下面条件下得到验证:
操作系统位数:32
编译器:gcc version 4.6.3(ubuntu)
mingw32-gcc
数据存储方式:小端存储
大端存储和小端存储
大端存储和小端存储指的是指内存地址的低位存的是数据的高位还是低位。
举个例子:int i=0x12345678
大端系统存储:
小端系统存储:
当数据从不同的系统流到不同的系统需要转换(字节序转换),最典型的是网络的大端字节序转换为x86的小端字节序
字节对齐
C语言的数据结构一般来说是不同数据类型的聚合物,里面包含了不同的数据类型,因为数据结构不会像C++的类那样给我们提供那么多的功能,所以它的存储就非常简单。仅仅是将数据直接按照顺序进行存储。比如下面这个数据结构:
struct str4_t
{
unsigned char c1[1];
unsigned char c2[2];
unsigned char c3[3];
unsigned char c4[5];
}str4;
它在内存中的就是按照顺序存储
sizeof(str4)的大小是11,1+2+3+5=11刚好。
怎么样?很简单吧!
不急呵,看看下面一个数据结构:
struct str3_t
{
unsigned char ac[3];
unsigned short s;
}str3;
应该是3+2=5吧。但是事实上呢sizeof(str3)是等于6的。为何呢?我们看看内存它是怎么存的:
上面黄色是ac,浅蓝色的是s。白色是没有存数据的。它被空出来了,这就是传说中的
字节对齐了。开头说了,我的操作系统是32位的,操作系统在我们的程序空间一次读出来的数据是32位(我们的程序内存是操作系统虚拟出来的),32位就是4个字节,如果上面把白色的去掉,我们访问s的时候就需要2次才能取到s的值,这样就很浪费时间啦。所以要字节序对齐。
再看看下面一个数据结构:
struct str2_t
{
unsigned short s;
unsigned int i;
unsigned char c;
}str2;
这个应该是多少呢?按照字节序对齐的原则应该是4+4+1=9.但是非常遗憾,结果是12.难道是因为str2这个数据结构要字节序对齐?这样也不对啊,上面的str3是6啊,也不是4的倍数啊。原因何在,百度、google之后发现还有一个规则:
结构体的整体大小必须是结构占用最大字节的成员的整数倍。str2最大是int型,就是4个字节,所以啊,只能是12了。
附:测试代码
#include <stdio.h>
#include <string.h>
#define BUFFERSIZE 120
unsigned char *p;
struct str1_t
{
unsigned char c;
unsigned short s;
unsigned int i;
unsigned long l;
}str1;
struct str2_t
{
unsigned short s;
unsigned int i;
unsigned char c;
}str2;
struct str3_t
{
unsigned char ac[3];
unsigned short s;
}str3;
struct str4_t
{
unsigned char c1[1];
unsigned char c2[2];
unsigned char c3[3];
unsigned char c4[5];
}str4;
int main()
{
int in,i,len;
in = 0x12345678;
p = (unsigned char *)∈
len = sizeof(in);
printf("int size:%d\r\n", len);
for(i=0; i<len; i++)
printf("%2X ", *(p+i));
printf("\r\n\r\n");
str1.c = 0x12;
str1.s = 0x34;
str1.i = 0x56;
str1.l = 0x78;
p = (unsigned char *)&str1;
len = sizeof(str1);
printf("str1 size:%d\r\n", len);
for(i=0; i<len; i++)
printf("%2X ", *(p+i));
printf("\r\n\r\n");
str2.s = 0x12;
str2.i = 0x34;
str2.c = 0x56;
p = (unsigned char *)&str2;
len = sizeof(str2);
printf("str2 size:%d\r\n", len);
for(i=0; i<len; i++)
printf("%2X ", *(p+i));
printf("\r\n\r\n");
str3.ac[0] = 0x12;
str3.ac[1] = 0x34;
str3.ac[2] = 0x56;
str3.s = 0x78;
p = (unsigned char *)&str3;
len = sizeof(str3);
printf("str3 size:%d\r\n", len);
for(i=0; i<len; i++)
printf("%2X ", *(p+i));
printf("\r\n\r\n");
str4.c1[0] = 0x1;
str4.c2[0] = 0x2;
str4.c2[1] = 0x3;
str4.c3[0] = 0x4;
str4.c3[1] = 0x5;
str4.c3[2] = 0x6;
str4.c4[0] = 0x7;
str4.c4[1] = 0x8;
str4.c4[2] = 0x9;
str4.c4[3] = 0xa;
str4.c4[4] = 0xb;
p = (unsigned char *)&str4;
len = sizeof(str4);
printf("str4 size:%d\r\n", len);
for(i=0; i<len; i++)
printf("%2X ", *(p+i));
printf("\r\n\r\n");
unsigned short s = 0xF1;
unsigned int i2 = 0xF2;
unsigned char c = 0xF3;
unsigned char buffer2[20];//avoid the memery overflow
memset(buffer2, 0 , sizeof(buffer2));
struct str2_t *pstr2;
pstr2 = (struct str2_t *)&s;
printf("%X %X %X\r\n", pstr2->s, pstr2->i, pstr2->c);
return 0;
}