1. #error 的用法
(1)#error 是一種預編譯器指示字,用於生成一個編譯錯誤消息
(2)用法:#error message //注意:message 不需要用雙引號包圍
(3)#error 編譯指示字用於自定義程序員特有的編譯錯誤消息。類似的,#warning 用於生成編譯警告消息
(4)#error 可用於提示編譯條件是否滿足。編譯過程中的任何錯誤意味着無法生成最終的可執行程序
2. #line 的用法
(1)#line 用於強制指定新的行號和編譯文件名,並對源程序的代碼重新編號
(2)用法:#line number newFilename //newFilename 可省略
(3)#line 編譯指示字的本質是重定義__LINE__和__FILE__
#include <stdio.h> //作者 A 寫的代碼 //--------------------------開始-------------------------- //把 line 的下一行定義為第 1 行,文件名為“a.c” #line 1 "a.c" //--------------------------結束-------------------------- //作者 B 寫的代碼 //--------------------------開始-------------------------- //把 line 的下一行定義為第 1 行,文件名為“b.c” #line 1 "b.c" //--------------------------結束-------------------------- //作者 C 寫的代碼 //--------------------------開始-------------------------- #line 1 "MyCode.c" int main(){ printf("%s:%d\n",__FILE__,__LINE__); #line 1 "Test.c" printf("%s:%d\n",__FILE__,__LINE__); return 0; } //--------------------------結束--------------------------
3.#pragma 的使用
(1)#pragma 用於指示編譯器完成一些特定的動作
(2)#pragma 所定義的很多指示字是編譯器特有的,在不同的編譯器間是不可移植的
①預處理器將忽略它不認識的#pragma 指令
②不同編譯器可能以不同的方式解釋同一條#pragma 指令
(3)一般用法:#pragma parameter //注意,不同的 parameter 參數語法和意義不同
3.1.#pragma message——用於自定義編譯消息
(1)message 參數在大多數的編譯器中都有相似的實現
(2)message 參數在編譯時輸出消息到編譯輸出窗口中
(3)message 用於條件編譯可提示代碼的版本信息
(4)與#error 和#warning 不同,#pragma message 僅僅代表一條編譯消息,不代表程序錯誤
#include <stdio.h> #if defined(ANDROID20) #pragma message("Complie Android SDK 2.0...") #define VERSION "Android 2.0" #elif defined(ANDROID23) #pragma message("Complie Android SDK 2.3...") #define VERSION "Android 2.3" #elif defined(ANDROID40) #pragma message("Complie 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; }
3.2.#pragma once——用於保證頭文件只被編譯一次
(1)#pragma once 用於保證頭文件只被編譯一次
(2)#pragma once 是編譯器相關的,不一定被支持(vc\gcc 都支持,bcc 不支持!)
(3)#pragma once 比#ifndef…#define…#endif 效率高,因為后者定義的頭文件仍然被處理。前者只要頭文件被定義一次,就不會再次被處理。
global.h
#pragma once int g_nValue = 1; //說明:因#pragma once 不被所有的編譯器支持(如 bcc 不支持),但 //#pragma once 又比#ifndef...#define...#endif 效率高,如果 //為了讓支持#pragma once 的編譯器有更高的效率有更高的效率,可以采用如下的頭文件定義方式/* #pragma once //當編譯器不支持#pragma once 時,會直接忽略這行 ifndef _HEADER_FILE_H_ #define _HEADER_FILE_H_ //source code #endif */
test.c
#include <stdio.h> #include "global.h" #include "global.h" //被 include 兩次 int main() { printf("g_nValue = %d \n",g_nValue); return 0; }
3.3.#pragma pack——用於指定內存對齊方式
(1)什么是內存對齊
不同類型的數據在內存中按照一定的規則排列而不一定是順序的一個接一個的排列。
結構體大小的計算
#include <stdio.h> #pragma pack(2) struct Test1 { char c1; //對齊參數:min(1,2)=1, offset = 0short s; //對齊參數: min(2,2)=2, offset = 2 char c2; //對齊參數:min(1,2)=1, offset = 4 int i; //對齊參數:min(4,2)=2, offset = 6 }; #pragma pack() #pragma pack(4) struct Test2 { char c1; //對齊參數:min(1,4)=1, offset = 0 char c2; //對齊參數:min(1,4)=1, offset = 1 short s; //對齊參數:min(2,4)=2, offset = 2 int i; //對齊參數:min(4,4)=4, offset = 4 }; #pragma pack() int main() { printf("sizeof(Test1) = %d\n",sizeof(struct Test1)); //10 printf("sizeof(Test2) = %d\n",sizeof(struct Test2)); //8 return 0; }
(2)為什么需要內存對齊?
CPU 對內存的讀取不是連續的,而是分成塊讀取的,塊的大小只能是 1、2、4、8、 16....字節,當讀取操作的數據未對齊,則需要兩次總線周期來訪問內存,此性能會大打折扣 ,某些硬件平台只能從規定的相對地址處讀取特定類型的數據,否則產生硬件異常
(3)#pragma pack(n)能夠改變編譯器的默認對齊方式(默認是按 4 字節對齊)
①struc 占用的內存大小
A.第一個成員起始於 0 偏移處
B.每個成員以 min(sizeof(成員的類型),n)的對齊參數進行對齊。即偏移地址必須 能被對齊參數整除,在復合結構體中,某個成員(結構體類型)的對齊參數為其內部長度最 大的數據成員的對齊參數作為這個成員的對齊參數。
②結構體總長度必須為所有對齊參數的整數倍。
#include <stdio.h> #define OFFSET(st,member) ((int)&((struct st*)0)->member) #pragma pack(1) struct S1 { short a; long b;//對齊參數:min(4,1)=1,sizeof(long)=4;->最大成員 }; #pragma pack() #pragma pack(2) struct S2 { char c;//offset = 0; struct S1 d;//offset = 1(對齊參數為 min(1,2)),sizeof(s1)=6; double e;//offset = 8(對齊參數為 min(8,2)) }; #pragma pack() int main() { printf("sizeof(struct S1) = %d\n",sizeof(struct S1));//6 printf("sizeof(struct S2) = %d\n",sizeof(struct S2));//16 printf("Member's Offset of Struct S2:\n"); printf("&s2.c=%d, &s2.d=%d, &s2.e=%d\n", OFFSET(S2,c),OFFSET(S2,d),OFFSET(S2,e)); return 0; }
參考資料:
www.dt4sw.com
http://www.cnblogs.com/5iedu/category/804081.html