- #pragma 用於指示編譯器完成一些特定的動做
- #pragma 所定義的不少指示字是編譯器特有的
#pragma 在不一樣的編譯器間是不可移植的編程
- 預處理器將忽略它不認識的#pragma指令
- 不一樣的編譯器可能以不一樣的方式解析同一條#pragma指令
通常用法:ide
'#pragma parameter' 注: 不一樣的 parameter 參數語法和意義各不相同
C 語言預留給編譯器廠商的擴展指示字性能
- message 參數在大多數的編譯器中都有類似的實現
- message 參數在編譯時輸出消息到編譯輸出窗口中
- message 用於條件編譯中可提示代碼的版本信息
#if defined(ANDROID20) #pragma message("Compile Android SDK 2.0 ...") #define VERSION "Android 2.0" #endif
與 #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; }
編譯輸出: [GCC] test.c:10: note: #pragma message: Compile Android SDK 4.0... [VC] Compile Android SDK 4.0... 運行輸出: [GCC] Android 4.0 [VC] Android 4.0
- #pragma once 用於保證頭文件只被編譯一次
- #pragma once 是編譯器相關的,不必定被支持
#ifndef _HEADER_H_ #define _HEADER_H_ // source code #endif
與spa
#pragma once
code
這兩種方式有什麼區別呢?ip
Test.c內存
#include <stdio.h> #include "global.h" #include "global.h" int main() { printf("g_value = %d\n", g_value); return 0; }
global.h編譯器
#pragma once int g_value = 1;
輸出: g_value = 1 VC GCC : 無警告,無錯誤 【主持】 BCC : 編譯出錯, g_value屢次定義 【不支持】
#ifndef _HEADER_H_ #define _HEADER_H_ #pragma once // source code #endif
什麼是內存對齊it
- 不一樣類型的數據在內存中按照必定的規則排列
- 而不必定是順序的一個接一個的排列
struct Test1 { char c1; short s2; char c2; int i; }; struct Test2 { char c1; char c2; short s2; int i; };
Test1 和 Test2 所佔的內存空間是否相同?io
sizeof(struct Test1) = 12
sizeof(struct Test2) = 8
CPU 對內存的讀取不是連續的,而是分紅塊讀取的,塊的大小隻能是一、二、四、八、16...字節
- 當讀取操做的數據未對齊,則須要兩次總線來訪問內存,所以性能會大打折扣
- 某些硬件平臺只能從規定的相對地址讀取特定類型的數據,不然產生硬件異常
- #pragm pack 用於指定內存對齊方式
未對齊形成兩次內存讀取【32位機器的讀寫最小粒度4字節】
#pragma pack(1) struct Test1 { char c1; short s2; char c2; int i; }; #pragma pack() #pragma pack(1) struct Test2 { char c1; char c2; short s2; int i; }; #pragma pack()
sizeof(struct Test1) = 8
sizeof(struct Test2) = 8
- 第一個成員起始於 0 偏移處
每一個成員按其類型大小和pack參數中較小的一個進行對齊
- 偏移地址必須能被對齊參數整除
- 結構體成員的對齊參數大小取其內部pack參數與內部長度最大的數據成員之間較小的做爲其對齊參數大小
- 結構體總長度必須爲全部對齊參數的整數倍
編譯器默認狀況下按照 4 字節對齊
編程實驗: 結構體大小計算
Test_1.c
#include <stdio.h> #pragma pack(2) struct Test1 { // 對齊參數 偏移地址 大小 char c1; // 1 0 1 short s2; // 2 2 2 char c2; // 1 5 2 int i; // 2 6 4 }; #pragma pack() #pragma pack(4) struct Test2 { // 對齊參數 偏移地址 大小 char c1; // 1 0 1 char c2; // 1 1 1 short s2; // 2 2 2 int i; // 4 4 4 }; #pragma pack() int main() { printf("%d\n", sizeof(struct Test1)); printf("%d\n", sizeof(struct Test2)); }
輸出: 10 8
Test_2.c
#include <stdio.h> #pragma pack(8) struct S1 { // 對齊參數 偏移地址 大小 short s; // 2 0 1 long b; // 4 4 4 }; // 總體長度爲全部對齊參數的整數倍, len = 4 + 4 = 8 struct S2 { // 對齊參數 偏移地址 大小 char c; // 1 0 1 struct S1 d; // 4 4 8 double e; // 8 16 8 }; // 總體長度爲全部對齊參數的整數倍 , len = 8 + 16 = 24 #pragma pack() int main() { printf("%d\n", sizeof(struct S1)); printf("%d\n", sizeof(struct S2)); }
輸出:[GCC] 8 20 【截至2018/12/04,GCC 暫不支持8字節對齊,忽略pack(8),默認4字節對齊】 輸出:[VC] 8 20
- #pragma 用於指示編譯器完成一些特定的動做
#pragma 所定義的不少指示字都是編譯器特有的
- #pragma message 用於自定義編譯消息
- #pragma once 用於保證頭文件只被編譯一次
- #pragma pack 用於指定內存對齊方式
以上內容參考狄泰軟件學院系列課程,請你們保護原創!