c語言——結構體偏移

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

參考資料

C 庫宏-offsetof()
C 標準庫-<stddef.h>
C 數據類型

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章