写在前面
工作几年了,由于信奉陶渊明的
“好读书,不求甚解”
(其实是懒)
的思想,很多概念其实了解的很模糊,最近工作中遇到一个问题:“64位环境下,指针占多少个字节?”,信誓旦旦的回答了4个字节,说指针无论32位环境下还是64位环境下,均占4个字节。
结果,可以想象,测试结果悲剧了。。。
这里格物致知一下,写了几个小demo,清晰一下混淆了很久的概念。
注:这里仅提供32和64位环境的测试结果,其实还有16位等,环境不好找,暂时放弃。
基本数据类型字节数
32位环境下字节数
char | bool | short int | int | long int | long long int | float | double | ptr | struct ptr |
---|---|---|---|---|---|---|---|---|---|
1 | 1 | 2 | 4 | 4 | 8 | 4 | 8 | 4 | 4 |
64位环境下字节数
char | bool | short int | int | long int | long long int | float | double | ptr | struct ptr |
---|---|---|---|---|---|---|---|---|---|
1 | 1 | 2 | 4 | 8 | 8 | 4 | 8 | 8 | 8 |
上面的表格,已经描述了大部分的差异,这里进一步解释一下特殊情况:
- 上面的short int/long int/long long int中的int可以省略。
- c标准中,并没有强制规定short < int < long,而是short <= int <= long,因此并不是说int就一定是4个字节,实际上,某些资料上说,16位环境下sizeof(int) = sizeof(short) = 2。
- 对于指针来说,32位平台下,4字节,64位平台下,8字节。
有关心测试用例和测试结果的朋友可以看看下面。
#include <stdio.h>
typedef struct tag_st
{
char b;
short w;
int dw;
} st;
int main(int argc, char* argv[])
{
printf("char size = %d\n", sizeof(char));
printf("short size = %d\n", sizeof(short));
printf("int size = %d\n", sizeof(int));
printf("long size = %d\n", sizeof(long));
printf("long int size = %d\n", sizeof(long int));
printf("long long int size = %d\n", sizeof(long long int));
printf("float size = %d\n", sizeof(float));
printf("double size = %d\n", sizeof(double));
printf("ptr size = %d\n", sizeof(char*));
printf("struct ptr size = %d\n", sizeof(st*));
return 0;
}
32位平台结果
bennett@linux-hycc:~/WorkSpace/test> gcc test.c -o test -m32
bennett@linux-hycc:~/WorkSpace/test> ./test
char size = 1
bool size = 1
short int size = 2
int size = 4
long int size = 4
long long int size = 8
float size = 4
double size = 8
ptr size = 4
struct ptr size = 4
64位平台结果
bennett@linux-hycc:~/WorkSpace/test> gcc test.c -o test -m64
bennett@linux-hycc:~/WorkSpace/test> ./test
char size = 1
bool size = 1
short int size = 2
int size = 4
long int size = 8
long long int size = 8
float size = 4
double size = 8
ptr size = 8
struct ptr size = 8
结构体的对齐和补齐
默认情况
数据类型 | 默认对齐字节 |
---|---|
基本类型 | sizeof(基本类型) |
数组 | sizeof(单个成员) |
联合 | sizeof(最大成员) |
结构体 | sizeof(每个成员) |
对齐:
默认情况下,基本数据类型按照自身大小整数倍进行对齐,即每个成员的首地址应该是自身大小的整数倍。
- 特殊的,对于数组成员,按照每个成员的大小进行对齐;
- 对于联合,按照最大成员大小进行对齐;
- 对于结构体内包含结构体的,递归的按照结构体的对齐方式对齐。
数据类型 | 默认补齐字节 |
---|---|
基本类型 | min(max(sizeof(基本类型)), 4) |
补齐:
默认情况下,按照最大成成员大小进行补齐,对于超过4字节的,按照4字节补齐。
#include <stdio.h>
typedef union tag_un
{
double ld1;
double ld2;
double ld3;
double ld4;
} un;
typedef struct tag_unn
{
short w;
char b;
} unn;
typedef struct tag_stt
{
double ld1;
double ld2;
double ld3;
} stt;
typedef struct tag_sttt
{
char arr1[11];
short arr2[1];
} sttt;
typedef struct tag_st
{
double ld;
char arr1[2];
char *ptr;
char b;
short arr2[18];
un un;
unn unn;
stt stt;
} st;
int main(int argc, char* argv[])
{
st st = {0.0, "ab", NULL};
printf("struct st size = %d\n", sizeof(st));
printf("struct sttt size = %d\n", sizeof(sttt));
printf("ld address = %p\n", &st.ld);
printf("arr1 address = %p\n", &st.arr1);
printf("ptr address = %p\n", &st.ptr);
printf("b address = %p\n", &st.b);
printf("arr2 address = %p\n", &st.arr2);
printf("un address = %p\n", &st.un);
printf("unn address = %p\n", &st.unn);
printf("stt address = %p\n", &st.stt);
return 0;
}
执行结果如下:
32位平台:
bennett@linux-hycc:~/WorkSpace/test> gcc test.c -o test -m32
bennett@linux-hycc:~/WorkSpace/test> ./test
struct st size = 92
struct sttt size = 14
ld address = 0xff962210
arr1 address = 0xff962218
ptr address = 0xff96221c
b address = 0xff962220
arr2 address = 0xff962222
un address = 0xff962248
unn address = 0xff962250
stt address = 0xff962254
64位平台:
bennett@linux-hycc:~/WorkSpace/test> gcc test.c -o test -m64
bennett@linux-hycc:~/WorkSpace/test> ./test
struct st size = 104
struct sttt size = 14
ld address = 0x7ffc512757c0
arr1 address = 0x7ffc512757c8
ptr address = 0x7ffc512757d0
b address = 0x7ffc512757d8
arr2 address = 0x7ffc512757da
un address = 0x7ffc51275800
unn address = 0x7ffc51275808
stt address = 0x7ffc51275810
编译器命令
#pragma pack(n)
对齐:
数据类型 | 默认对齐字节 |
---|---|
基本类型 | min(sizeof(基本类型), n) |
数组 | min(sizeof(单个成员), n) |
联合 | min(sizeof(最大成员), n) |
结构体 | min(sizeof(每个成员), n) |
补齐:
数据类型 | 默认补齐字节 |
---|---|
基本类型 | min(max(sizeof(基本类型)), n) |
写在结尾
想着好好写来的,结果用例的名字还是乱七八糟,暂时不改了,有机会再调整吧。