C語言進階:24、#pragma使用分析

#pragma用於指示完成一些特定的動作,並且所定義的很多指示字是編譯器特有的。

#pragma在不同的編譯器間是不可移植的
——預處理器將忽略它不認識的#pragma指令
——不同的編譯器可能以不同的方式解釋一條#pragma指令。

一般用法:

	#pragma parameter
	注:不同的parameter參數語法和意義各不相同
message參數在大多數的編譯器中都有相似的實現;

message參數在編譯時輸出消息到編譯輸出窗口中。

與#error和#warning不同,#pragma message僅僅代表一條編譯消息,不代表程序錯誤。

#include <stdio.h>

#if defined(ANDROID20)
    #pragma message("Compile Android SDK 2.0...")
    #define VERSION "Android 2.0"
#elif defined(ANDROID23)
    #pragma message("Compile Android SDK 2.3...")
    #define VERSION "Android 2.3"
#elif defined(ANDROID40)
    #pragma message("Compile Android SDK 4.0...")
    #define VERSION "Android 4.0"
#else
    #error Compile Version is not provided!
#endif

int main()
{
    printf("%s\n", VERSION);

    return 0;
}

在Linux下使用GCC進行編譯:

~/will$ gcc 24-1.c   //直接編譯
24-1.c:13: error: #error Compile Version is not provided!
24-1.c: In function ‘main’:
24-1.c:18: error: ‘VERSION’ undeclared (first use in this function)
24-1.c:18: error: (Each undeclared identifier is reported only once
24-1.c:18: error: for each function it appears in.)
~/will$ 
~/will$ 
~/will$ gcc -DANDROID23  24-1.c   // 條件編譯
24-1.c:7: note: #pragma message: Compile Android SDK 2.3...    //與VC不同的是,BCC和GCC將 #pragma message: 打印出來
~/will$ 
~/will$ 
~/will$ ./a.out   //運行
Android 2.3

#pragma once

#pragma once 用於保證頭文件紙杯編譯一次;

#pragma once 是編譯器相關,不一定被支持。


pragma once是部分編譯器支持;預處理器遇見pragma once後將直接忽略再次出現的頭文件

#pragma pack  內存對齊

——不同類型的數據在內存中按照一定的規則排列
——而不一定是順序的一個接一個的排列

爲什麼需要內存對齊?
——CPU對內存的讀取不是連續的,而是分成塊讀取的,快的大小隻能是1,2,4,8,16...字節;
——當讀取操作的數據未對齊,則需要兩次總線週期來訪問內存,因此性能會大打折扣;
——某些硬件平臺只能從規定的相對地址處讀取特定類型的數據,否則產生硬件異常。

#pragma pack用於指定“內存對齊”方式。

#include <stdio.h>

#pragma pack(4)

struct Test1
{    		        //對齊參數	 偏移地址		大小
	char  c1;     //1    		0			1(4)
    short s;          //2   		2			2   
    char  c2;         //1    		4			1(4)
    int   i;          //4    		8			4
};
#pragma pack()
#pragma pack(4)
struct Test2
{		 //對齊參數	        偏移地址		        大小
    char  c1;    //1     		0			1
    char  c2;    //1     		1			1
    short s;     //2     		2			2
    int   i;     //4     		4			4
};
#pragma pack()
int main()
{
    printf("sizeof(Test1) = %d\n", sizeof(struct Test1));
    printf("sizeof(Test2) = %d\n", sizeof(struct Test2));

    return 0;
}

編譯運行:

~/will$ ./a.out
sizeof(Test1) = 12
sizeof(Test2) = 8

Gcc編譯器暫時不支持8字節對齊

struct佔用的內存大小:
——第一個成員起始於0偏移處;
——每個成員按其類型大小和pack參數中較小的一個進行對齊;
偏移地址必須能被對齊參數整除
結構體成員的大小取其內部長度最大的數據成員作爲其大小;

結構體總長度必須爲所有對齊參數的整數倍

注意:編譯器在默認情況下按照4字節對齊。
#include <stdio.h>
#pragma pack(8)
struct S1
{               //對齊參數      偏移地址        大小
    short a;    //2             0            2  
    long b;     //4             4            4
};
struct S2
{                   //對齊參數      偏移地址        大小
    char c;         //1             0              1
    struct S1 d;    //4             4              8
    double e;       //8             16             8
};

#pragma pack()
int main()
{
    printf("%d\n", sizeof(struct S1));
    printf("%d\n", sizeof(struct S2));
    return 0;

}
Gcc編譯器暫時不支持8字節對齊,輸出爲
8
20
在vc編譯器支持8字節對齊,輸出爲
8
24

小結:

#pragma用於指示編譯器完成一些特定的動作

 #pragma所定義的很多指示字是編譯器特有

——#pragma message用於自定義編譯消息
——#pragma once用於保證頭文件只被編譯一次
——#pragma pack用於指定內存對齊方式


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