C語言 結構體(聯合體)對齊規則

/* 結構體(聯合體)對齊規則 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/*
    * 原則一、第一個數據成員放在offset爲0的地方,之後每一個數據成員存儲的起始位置要從該成員大小的整數倍開始(好比int在32位機爲4字節,則要從4的整數倍地址開始存儲)。

    * 原則二、結構體做爲成員:若是一個結構裏有某些結構體成員,則結構體成員要從其內部最寬基本類型大小的整數倍地址開始存儲。

    *原則三、結構體的總大小爲結構體最寬基本類型成員(成員能夠是基本類型,也能夠是結構體)大小的整數倍,若有須要編譯器會在最末一個成員以後加上填充字節

    *最寬基本類型的概念,所謂基本類型是指像char、short、int、float、double這樣的內置數據類型。

*/

struct Data1
{
    int c;   
    char a;  
    char b;  
};

/*
struct Data1分析
分析對齊數
對齊數的值是 結構體中最寬基本類型成員
struct Data1最寬類型是int,佔4個字節大小,因此對齊數的值是4

根據原則1(第一個數據成員放在offset爲0的地方),成員屬性c從offset爲0的位置開始,成員屬性c大小是4個字節,成員屬性c從offset爲0的位置開始存儲,佔據4個字節大小

成員屬性a從offset爲4的位置開始,根據原則1(之後每一個數據成員存儲的起始位置要從該成員大小的整數倍開始) ,如今offset是4,是1的整數倍
因此成員屬性a從offset爲4的位置開始存儲,佔據1個字節大小

成員屬性b從offset爲5的位置開始,根據原則1(之後每一個數據成員存儲的起始位置要從該成員大小的整數倍開始) ,如今offset是5,是1的整數倍
因此成員屬性b從offset爲5的位置開始存儲,佔據1個字節大小

如今struct Data1一共佔據6個字節大小的空間,根據原則3(必須是其內部最大成員的整數倍),struct Data1最寬基本類型是int,佔4個字節大小
所以結構體的總大小必須是4的倍數,6不是4的倍數,補齊2個字節,變成8個字節
結論:struct Data1 大小是8個字節

*/

struct Data2
{
    char a;  
    int c;   
    char b;  
};

/*
struct Data2分析
分析對齊數
struct Data2最寬類型是int,佔4個字節大小,因此對齊數的值是4

根據原則1(第一個數據成員放在offset爲0的地方),成員屬性a從offset爲0的位置開始,成員屬性a大小是1個字節,成員屬性a從offset爲0的位置開始存儲,佔據1個字節大小

成員屬性c是int類型,根據原則1(之後每一個數據成員存儲的起始位置要從該成員大小的整數倍開始),如今offset是1,1不是4的整數倍
編譯器填充3個字節,如今offset爲4 , 4是int的整數倍,成員屬性c從offset爲4的位置開始存儲,佔據4個字節大小

成員屬性b從offset爲8的位置開始,根據原則1(之後每一個數據成員存儲的起始位置要從該成員大小的整數倍開始) ,如今offset是8,是1的整數倍
因此成員屬性b從offset爲8的位置開始存儲,佔據1個字節大小

如今struct Data2一共佔據9個字節大小的空間,根據原則3(必須是其內部最大成員的整數倍),struct Data2最寬基本類型是int,佔4個字節大小
所以結構體的總大小必須是4的倍數,9不是4的倍數,補齊3個字節,變成12個字節
結論:struct Data1 大小是12個字節

*/

struct Data3
{
    char a;
    short b;
    double c;
};

/*
struct Data3分析
分析對齊數
struct Data3最寬類型是double,佔8個字節大小,因此對齊數的值是8

根據原則1(第一個數據成員放在offset爲0的地方),成員屬性a從offset爲0的位置開始,成員屬性a大小是1個字節,成員屬性a從offset爲0的位置開始存儲,佔據1個字節大小

成員屬性b從offset爲1的位置開始,根據原則1(之後每一個數據成員存儲的起始位置要從該成員大小的整數倍開始) ,如今offset是1,不是short的整數倍
編譯器填充1個字節,如今offset爲2 , 2是short的整數倍,成員屬性b從offset爲2的位置開始存儲,佔據2個字節大小

成員屬性c從offset爲4的位置開始,根據原則1(之後每一個數據成員存儲的起始位置要從該成員大小的整數倍開始) ,如今offset是4,不是double的整數倍
編譯器填充4個字節,如今offset爲8 , 8是double的整數倍,成員屬性c從offset爲8的位置開始存儲,佔據8個字節大小

如今struct Data3一共佔據16個字節大小的空間,根據原則3(必須是其內部最大成員的整數倍),struct Data3最寬基本類型是double,佔8個字節大小
所以結構體的總大小必須是8的倍數,16是8的倍數,不用填充字節
結論:struct Data3 大小是16個字節

*/

struct Data4
{
    short a;
    char b;
    double c;
    char d[5];
};

/*
struct Data4分析
分析對齊數
struct Data3最寬類型是double,佔8個字節大小,因此對齊數的值是8
char d[5]並不是基本類型

根據原則1(第一個數據成員放在offset爲0的地方),成員屬性a從offset爲0的位置開始,成員屬性a大小是2個字節,成員屬性a從offset爲0的位置開始存儲,佔據2個字節大小

成員屬性b從offset爲2的位置開始,根據原則1(之後每一個數據成員存儲的起始位置要從該成員大小的整數倍開始) ,如今offset是2,是1的整數倍
成員屬性b從offset爲2的位置開始存儲,佔據1個字節大小

成員屬性c從offset爲3的位置開始,根據原則1(之後每一個數據成員存儲的起始位置要從該成員大小的整數倍開始) ,如今offset是3,不是double的整數倍
編譯器填充5個字節,如今offset爲8 , 8是double的整數倍,成員屬性c從offset爲8的位置開始存儲,佔據8個字節大小

成員屬性d從offset爲16的位置開始,根據原則1(之後每一個數據成員存儲的起始位置要從該成員大小的整數倍開始) ,如今offset是16,是char的整數倍
成員屬性d從offset爲16的位置開始存儲,佔據1個字節大小

如今struct Data4一共佔據17個字節大小的空間,根據原則3(必須是其內部最大成員的整數倍),struct Data3最寬基本類型是double,佔8個字節大小
所以結構體的總大小必須是8的倍數,17不是8的倍數,須要填充7個字節
結論:struct Data4 大小是24個字節

*/

struct Data5
{
    short a;
    struct Data4 b;
};

/*
struct Data5分析
分析對齊數
根據原則2, struct Data4最寬類型是double 佔8個字節大小,而struct Data5成員a佔2個字節,因此對齊數的值是8

根據原則1(第一個數據成員放在offset爲0的地方),成員屬性a從offset爲0的位置開始,成員屬性a大小是2個字節,成員屬性a從offset爲0的位置開始存儲,佔據2個字節大小

成員屬性b從offset爲2的位置開始,根據原則2(結構體成員要從其內部最大元素大小的整數倍地址開始存儲) ,如今offset是2,不是double的整數倍
編譯器填充6個字節,如今offset爲8 , 8是double的整數倍,成員屬性b從offset爲8的位置開始存儲,佔據24個字節大小

如今struct Data5一共佔據32個字節大小的空間,根據原則3(必須是其內部最大成員的整數倍),struct Data5最寬基本類型是double,佔8個字節大小
所以結構體的總大小必須是8的倍數,32是8的倍數,不須要填充字節
結論:struct Data5 大小是32個字節

*/

struct Data6
{
    double a;
    struct Data1 b;
};

/*
struct Data6分析
分析對齊數
根據原則2, struct Data1最寬類型是int 佔4個字節大小,而struct Data5成員a 佔8個字節,因此對齊數的值是8

根據原則1(第一個數據成員放在offset爲0的地方),成員屬性a從offset爲0的位置開始,成員屬性a大小是8個字節,成員屬性a從offset爲0的位置開始存儲,佔據8個字節大小

成員屬性b從offset爲8的位置開始,根據原則2(結構體成員要從其內部最大元素大小的整數倍地址開始存儲) ,如今offset是8 ,是 int 的整數倍
成員屬性b從offset爲8的位置開始存儲,佔據8個字節大小

如今struct Data6一共佔據16個字節大小的空間,根據原則3(必須是其內部最大成員的整數倍),struct Data6最寬基本類型是double,佔8個字節大小
所以結構體的總大小必須是8的倍數,16是8的倍數,不須要填充字節
結論:struct Data6 大小是16個字節

*/

void test()
{
    printf("----struct size---1-[%d]------\n", sizeof(struct Data1));   //8
    printf("----struct size--2--[%d]------\n", sizeof(struct Data2));   //12
    printf("----struct size--3--[%d]------\n", sizeof(struct Data3));   //16
    printf("----struct size--4--[%d]------\n", sizeof(struct Data4));   //24
    printf("----struct size--5--[%d]------\n", sizeof(struct Data5));   //32
    printf("----struct size--6--[%d]------\n", sizeof(struct Data6));   //16
}

int main()
{
    test();
    printf("-----ok------\n");
    getchar();
    return 0;
}
相關文章
相關標籤/搜索