c語言——結構體偏移
學習結構體偏移前,我們先複習一下c語言的數據類型、結構體對齊。
整數類型
下表列出了關於標準整數類型的存儲大小和值範圍的細節:
類型 | 存儲大小 | 值範圍 |
---|---|---|
char | 1 字節 | -128 到 127 或 0 到 255 |
unsigned char | 1 字節 | 0 到 255 |
signed char | 1 字節 | -128 到 127 |
int | 2 或 4 字節 | -32,768 到 32,767 或 -2,147,483,648 到 2,147,483,647 |
unsigned int | 2 或 4 字節 | 0 到 65,535 或 0 到 4,294,967,295 |
short | 2 字節 | -32,768 到 32,767 |
unsigned short | 2 字節 | 0 到 65,535 |
long | 4 字節 | -2,147,483,648 到 2,147,483,647 |
unsigned long | 4 字節 | 0 到 4,294,967,295 |
注意,各種類型的存儲大小與系統位數有關,但目前通用的以64位系統爲主。
以下列出了32位系統與64位系統的存儲大小的差別(windows 相同):
爲了得到某個類型或某個變量在特定平臺上的準確大小,您可以使用 sizeof 運算符。表達式 sizeof(type) 得到對象或類型的存儲字節大小。
浮點類型
下表列出了關於標準浮點類型的存儲大小、值範圍和精度的細節:
類型 | 存儲大小 | 值範圍 | 精度 |
---|---|---|---|
float | 4 字節 | 1.2E-38 到 3.4E+38 | 6 位小數 |
double | 8 字節 | 2.3E-308 到 1.7E+308 | 15 位小數 |
long double | 16 字節 | 3.4E-4932 到 1.1E+4932 | 19 位小數 |
結構體對齊
結構體計算要遵循字節對齊原則。
結構體默認的字節對齊一般滿足三個準則:
- 結構體變量的首地址能夠被其最寬基本類型成員的大小所整除;
- 結構體每個成員相對於結構體首地址的偏移量(offset)都是成員大小的整數倍,如有需要編譯器會在成員之間加上填充字節(internal adding);
- 結構體的總大小爲結構體最寬基本類型成員大小的整數倍,如有需要編譯器會在最末一個成員之後加上填充字節(trailing padding)
例子
#include <stddef.h>
#include <stdio.h>
struct address {
char name[50];
char street[50];
int phone;
};
int main()
{
printf("address 結構中的 name 偏移 = %d 字節。\n",
offsetof(struct address, name));
printf("address 結構中的 street 偏移 = %d 字節。\n",
offsetof(struct address, street));
printf("address 結構中的 phone 偏移 = %d 字節。\n",
offsetof(struct address, phone));
return(0);
}
運行
address 結構中的 name 偏移 = 0 字節。
address 結構中的 street 偏移 = 50 字節。
address 結構中的 phone 偏移 = 100 字節。
結構體成員偏移量
test01
struct A
{
char a1; //0
int a2; //4-7
};
void test01()
{
struct A a = { 'b', 20 };
printf("A.a2:%d\n", *(int *)((char *)&a + offsetof(struct A, a2)));
printf("A.a2:%d\n", *((int *)&a + 1) );
}
運行
A.a2:20
A.a2:20
test02
struct B
{
char a;
int b;
struct C c;
};
void test02()
{
struct B b = { 'a', 20, 30, 3.14 };
int off1 = offsetof(struct B, c);
int off2 = offsetof(struct C, b);
printf("off1=%d\n", off1);
printf("off2=%d\n", off2);
printf("%f\n", *(double *)(((char *)&b + off1) + off2));
printf("%d\n", &(b.c.b));
printf("%f\n", ((struct C *)((char *)&b + off1))->b );
}
運行
off1=8
off2=8
3.140000
11533292
3.140000
test03
struct Student{
int a; //0-3
char b; //4-7
double c; //8-15
float d;//16-19
};
void test03()
{
printf("%d\n", sizeof(struct Student));
}
運行
24
因爲結構體對齊,所以8 * 3 = 24
。