c/c++标准预定义宏
轉自:http://www.eefocus.com/andysun001/blog/10-06/192018_008b3.html
?
一、標準預定義宏
The standard predefined macros are specified by the relevant language standards, so they are available with all compilers that implement those standards. Older compilers may not provide all of them. Their names all start with double underscores.
__FILE__
This macro expands to the name of the current input file, in the form of a C string constant. This is the path by which the preprocessor opened the file, not the short name specified in #include or as the input file name argument. For example, "/usr/local/include/myheader.h" is a possible expansion of this macro.
__LINE__
This macro expands to the current input line number, in the form of a decimal integer constant. While we call it a predefined macro, it's a pretty strange macro, since its "definition" changes with each new line of source code.
__FILE__ and __LINE__ are useful in generating an error message to report an inconsistency detected by the program; the message can state the source line at which the inconsistency was detected. For example,
???? fprintf (stderr, "Internal error: "
????????????????????? "negative string length "
????????????????????? "%d at %s, line %d.",
????????????? length, __FILE__, __LINE__);
????
An #include directive changes the expansions of __FILE__ and __LINE__ to correspond to the included file. At the end of that file, when processing resumes on the input file that contained the #include directive, the expansions of __FILE__ and __LINE__ revert to the values they had before the #include (but __LINE__ is then incremented by one as processing moves to the line after the #include).
A #line directive changes __LINE__, and may change __FILE__ as well. See Line Control.
C99 introduces __func__, and GCC has provided __FUNCTION__ for a long time. Both of these are strings containing the name of the current function (there are slight semantic differences; see the GCC manual). Neither of them is a macro; the preprocessor does not know the name of the current function. They tend to be useful in conjunction with __FILE__ and __LINE__, though.
__DATE__
This macro expands to a string constant that describes the date on which the preprocessor is being run. The string constant contains eleven characters and looks like "Feb 12 1996". If the day of the month is less than 10, it is padded with a space on the left.
If GCC cannot determine the current date, it will emit a warning message (once per compilation) and __DATE__ will expand to "??? ?? ????".
__TIME__
This macro expands to a string constant that describes the time at which the preprocessor is being run. The string constant contains eight characters and looks like "23:59:01".
If GCC cannot determine the current time, it will emit a warning message (once per compilation) and __TIME__ will expand to "??:??:??".
__STDC__
In normal operation, this macro expands to the constant 1, to signify that this compiler conforms to ISO Standard C. If GNU CPP is used with a compiler other than GCC, this is not necessarily true; however, the preprocessor always conforms to the standard unless the -traditional-cpp option is used.
This macro is not defined if the -traditional-cpp option is used.
On some hosts, the system compiler uses a different convention, where __STDC__ is normally 0, but is 1 if the user specifies strict conformance to the C Standard. CPP follows the host convention when processing system header files, but when processing user files __STDC__ is always 1. This has been reported to cause problems; for instance, some versions of Solaris provide X Windows headers that expect __STDC__ to be either undefined or 1. See Invocation.
__STDC_VERSION__
This macro expands to the C Standard's version number, a long integer constant of the form yyyymmL where yyyy and mm are the year and month of the Standard version. This signifies which version of the C Standard the compiler conforms to. Like __STDC__, this is not necessarily accurate for the entire implementation, unless GNU CPP is being used with GCC.
The value 199409L signifies the 1989 C standard as amended in 1994, which is the current default; the value 199901L signifies the 1999 revision of the C standard. Support for the 1999 revision is not yet complete.
This macro is not defined if the -traditional-cpp option is used, nor when compiling C++ or Objective-C.
__STDC_HOSTED__
This macro is defined, with value 1, if the compiler's target is a hosted environment. A hosted environment has the complete facilities of the standard C library available.
__cplusplus
This macro is defined when the C++ compiler is in use. You can use __cplusplus to test whether a header is compiled by a C compiler or a C++ compiler. This macro is similar to __STDC_VERSION__, in that it expands to a version number. A fully conforming implementation of the 1998 C++ standard will define this macro to 199711L. The GNU C++ compiler is not yet fully conforming, so it uses 1 instead. We hope to complete our implementation in the near future.
__OBJC__
This macro is defined, with value 1, when the Objective-C compiler is in use. You can use __OBJC__ to test whether a header is compiled by a C compiler or a Objective-C compiler.
__ASSEMBLER__
This macro is defined with value 1 when preprocessing assembly language.
?
C標準中的一些預定義宏昨天寫代碼時需要在代碼獲取當前編譯時間,從而可動態地作為版本信息,因此用到了C標準中的一些預定義的宏。在此將C標準中定義的幾個宏一并總結一下:
?
__DATE__ 進行預處理的日期(“Mmm dd yyyy”形式的字符串文字,如May 27 2006)
__FILE__ 代表當前源代碼文件名的字符串文字 ,包含了詳細路徑,如G:/program/study/c+/test1.c
__LINE__ 代表當前源代碼中的行號的整數常量
__TIME__ 源文件編譯時間,格式微“hh:mm:ss”,如:09:11:10;
__func__ 當前所在函數名,在編譯器的較高版本中支持
__FUNCTION__ 當前所在函數名
對于__FILE__,__LINE__,__func__,__FUNCTION__ 這樣的宏,在調試程序時是很有用的,因為你可以很容易的知道程序運行到了哪個文件的那一行,是哪個函數。
而對于__DATE__,__TIME__則可以獲取編譯時間,如如下代碼通過宏獲取編譯時間,并通過sscanf()從中獲取具體的年月日時分秒數據,可在代碼中做相應使用。我的代碼中是根據此數據作為版本標識,并依此判斷哪個版本新些及是否需要升級。
char * creationDate?? = __DATE__ ", " __TIME__;
sscanf(creationDate, "%s %d %d, %d:%d:%d", month, &day, &year, &hour, &min, &sec);
?
?
預處理命令#pragma和預定義宏--轉載
一、C預定義宏
C標準指定了一些預定義宏,編程中常常用到。
__DATE__???? 進行預處理的日期
__FILE__???? 代表當前源代碼文件名的字符串
__LINE__???? 代表當前源代碼文件中行號的整數常量
__STDC__???? 設置為1時,表示該實現遵循C標準
__STDC_HOSTED__? 為本機環境設置為,否則設為0
__STDC_VERSION__ 為C99時設置為199901L
__TIME__???? 源文件的編譯時間
__func__???? C99提供的,為所在函數名的字符串
對于__FILE__,__LINE__,__func__這樣的宏,在調試程序時是很有用的,因為你可以很容易的知道程序運行到了哪個文件的那一行,是哪個函數.
例如:
#include
#include
void why_me();
int main()
{
??? printf( "The file is %s/n", __FILE__ );
??? printf( "The date is %s/n", __DATE__ );
??? printf( "The time is %s/n", __TIME__ );
??? printf("The version is %s/n",__STDC__VERSION__);
??? printf( "This is line %d/n", __LINE__ );
??? printf( "This function is %s/n ", __func__ );
?? why_me();
?? return 0;
}
void why_me()
{
??? printf( "This function is %s/n", __func__ );
??? printf( "This is line %d/n", __LINE__ );
}
二、#line和#error
#line用于重置由__LINE__和__FILE__宏指定的行號和文件名。
用法如下:#line number filename
例如:#line 1000 //將當前行號設置為1000
?????#line 1000 "lukas.c"?? //行號設置為1000,文件名設置為lukas.c
#error指令使預處理器發出一條錯誤消息,該消息包含指令中的文本.這條指令的目的就是在程序崩潰之前能夠給出一定的信息。
三、#pragma
在所有的預處理指令中,#Pragma 指令可能是最復雜的了。#pragma的作用是設定編譯器的狀態或者是指示編譯器完成一些特定的動作。#pragma指令對每個編譯器給出了一個方法,在保持與C和C++語言完全兼容的情況下,給出主機或操作系統專有的特征。依據定義,編譯指示是機器或操作系統專有的,且對于每個編譯器都是不同的。
其格式一般為: #Pragma Para
其中Para 為參數,下面來看一些常用的參數。
(1)message 參數。 Message 參數是我最喜歡的一個參數,它能夠在編譯信息輸出窗口中輸出相應的信息,這對于源代碼信息的控制是非常重要的。其使用方法為:
#Pragma message(“消息文本”)
當編譯器遇到這條指令時就在編譯輸出窗口中將消息文本打印出來。
當我們在程序中定義了許多宏來控制源代碼版本的時候,我們自己有可能都會忘記有沒有正確的設置這些宏,此時我們可以用這條指令在編譯的時候就進行檢查。假設我們希望判斷自己有沒有在源代碼的什么地方定義了_X86這個宏可以用下面的方法
#ifdef _X86
#Pragma message(“_X86 macro activated!”)
#endif
當我們定義了_X86這個宏以后,應用程序在編譯時就會在編譯輸出窗口里顯示“_
X86 macro activated!”。我們就不會因為不記得自己定義的一些特定的宏而抓耳撓腮了。
(2)另一個使用得比較多的pragma參數是code_seg。格式如:
#pragma code_seg( ["section-name"[,"section-class"] ] )
它能夠設置程序中函數代碼存放的代碼段,當我們開發驅動程序的時候就會使用到它。
(3)#pragma once (比較常用)
只要在頭文件的最開始加入這條指令就能夠保證頭文件被編譯一次。這條指令實際上在VC6中就已經有了,但是考慮到兼容性并沒有太多的使用它。
(4)#pragma hdrstop表示預編譯頭文件到此為止,后面的頭文件不進行預編譯。BCB可以預編譯頭文件以加快鏈接的速度,但如果所有頭文件都進行預編譯又可能占太多磁盤空間,所以使用這個選項排除一些頭文件。
有時單元之間有依賴關系,比如單元A依賴單元B,所以單元B要先于單元A編譯。你可以用#pragma startup指定編譯優先級,如果使用了#pragma package(smart_init) ,BCB就會根據優先級的大小先后編譯。
(5)#pragma resource "*.dfm"表示把*.dfm文件中的資源加入工程。*.dfm中包括窗體外觀的定義。
(6)#pragma warning( disable : 4507 34; once : 4385; error : 164 )等價于:
#pragma warning(disable:4507 34) /* 不顯示4507和34號警告信息。如果編譯時總是出現4507號警告和34號警告,
????????????????????????????????????而認為肯定不會有錯誤,可以使用這條指令。*/
#pragma warning(once:4385) // 4385號警告信息僅報告一次
#pragma warning(error:164) // 把164號警告信息作為一個錯誤。
同時這個pragma warning 也支持如下格式:
#pragma warning( push [ ,n ] )
#pragma warning( pop )
這里n代表一個警告等級(1---4)。
#pragma warning( push )保存所有警告信息的現有的警告狀態。
#pragma warning( push, n)保存所有警告信息的現有的警告狀態,并且把全局警告等級設定為n。
#pragma warning( pop )向棧中彈出最后一個警告信息,在入棧和出棧之間所作的一切改動取消。例如:
#pragma warning( push )
#pragma warning( disable : 4705 )
#pragma warning( disable : 4706 )
#pragma warning( disable : 4707 )
//.......
#pragma warning( pop )
在這段代碼的最后,重新保存所有的警告信息(包括4705,4706和4707)。
(7)pragma comment(...)
該指令將一個注釋記錄放入一個對象文件或可執行文件中。
常用的lib關鍵字,可以幫我們連入一個庫文件。
(8)progma pack(n)
??? 指定結構體對齊方式!#pragma pack(n)來設定變量以n字節對齊方式。n 字節對齊就是說變量存放的起始地址的偏移量有兩種情況:第一、如果n大于等于該變量所占用的字節數,那么偏移量必須滿足默認的對齊方式,第二、如果n小于該變量的類型所占用的字節數,那么偏移量為n的倍數,不用滿足默認的對齊方式。結構的總大小也有個約束條件,分下面兩種情況:如果n大于所有成員變量類型所占用的字節數,那么結構的總大小必須為占用空間最大的變量占用的空間數的倍數; 否則必須為n的倍數。下面舉例說明其用法。
#pragma pack(push) //保存對齊狀態
#pragma pack(4)//設定為4字節對齊
struct test
{
char m1;
double m4;
int m3;
};
#pragma pack(pop)//恢復對齊狀態
為測試該功能,可以使用sizeof()測試結構體的長度!
?
?
?在你寫dll的時候,因為對于C和C++,編譯器會有不同的名字解析規則,所以可以這樣用
#ifndef ? __STDC__
extern "C " ? void ? function();
#else
void ? function();
#endif
?
?__LINE__?????????? 在源代碼中插入當前源代碼行號
? __FILE__?????????? 在源代碼中插入當前源代碼文件名
? __DATE__?????????? 在源代碼中插入當前編譯日期〔注意和當前系統日期區別開來〕
? __TIME__?????????? 在源代碼中插入當前編譯時間〔注意和當前系統時間區別開來〕??
? __STDC__?????????? 當要求程序嚴格遵循ANSIC標準時該標識符被賦值為1。
----------------------------------------------------------------------------
標識符__LINE__和__FILE__通常用來調試程序;標識符__DATE__和__TIME__通常用來在編譯后的程序中加入一個時間標志,以區分程序的不同版本;當要求程序嚴格遵循ANSIC標準時,標識符__STDC__就會被賦值為1;當用C++編譯程序編譯時,標識符__cplusplus就會被定義。
#include
?
int main ()
{
??? printf("該輸出行在源程序中的位置:%d/n", __LINE__ );
??? printf("該程序的文件名為:%s/n", __FILE__ );
??? printf("當前日期為:%s/n", __DATE__ );
??? printf("當前時間為:%s/n", __TIME__ );
?
??? return 0;
}
?
#include
void main(void)
{
??? printf("%d",__LINE__); // Line 5
}
結果為:5
?
?
// 標準預定義宏宏.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include
void main(void)
{
???? printf("%d",__LINE__); // Line 5
?}
?
?
編譯器宏使用總結
C/C++中宏總結C程序的源代碼中可包括各種編譯指令,這些指令稱為預處理命令。雖然它們實際上不是C語言的一部分,但卻擴展了C程序設計的環境。本節將介紹如何應用預處理程序和注釋簡化程序開發過程,并提高程序的可讀性。ANSI標準定義的C語言預處理程序包括下列命令:
?
#define,#error,#include,#if,#else,#elif,#endif,#ifdef,#ifndef,#undef,#line,#pragma等。非常明顯,所有預處理命令均以符號#開頭,下面分別加以介紹。
?
命令#define定義了一個標識符及一個串。在源程序中每次遇到該標識符時,均以定義的串代換它。ANSI標準將標識符定義為宏名,將替換過程稱為宏替換。命令的一般形式為:
?
#define identifier string
?
注意:
? 該語句沒有分號。在標識符和串之間可以有任意個空格,串一旦開始,僅由一新行結束。
? 宏名定義后,即可成為其它宏名定義中的一部分。
? 宏替換僅僅是以文本串代替宏標識符,前提是宏標識符必須獨立的識別出來,否則不進行替換。例如:
#define XYZ this is a tes
使用宏printf("XYZ");//該段不打印"this is a test"而打印"XYZ"。因為預編譯器識別出的是"XYZ"
? 如果串長于一行,可以在該行末尾用一反斜杠' /'續行。
?
處理器命令#error強迫編譯程序停止編譯,主要用于程序調試。
?
#include 命令#i nclude使編譯程序將另一源文件嵌入帶有#i nclude的源文件,被讀入的源文件必須用雙引號或尖括號括起來。例如:
?
#i nclude"stdio.h"或者#i nclude
?
這兩行代碼均使用C編譯程序讀入并編譯用于處理磁盤文件庫的子程序。
將文件嵌入#i nclude命令中的文件內是可行的,這種方式稱為嵌套的嵌入文件,嵌套層次依賴于具體實現。
?
如果顯式路徑名為文件標識符的一部分,則僅在哪些子目錄中搜索被嵌入文件。否則,如果文件名用雙引號括起來,則首先檢索當前工作目錄。如果未發現文件,則在命令行中說明的所有目錄中搜索。如果仍未發現文件,則搜索實現時定義的標準目錄。
?
如果沒有顯式路徑名且文件名被尖括號括起來,則首先在編譯命令行中的目錄內檢索。
?
如果文件沒找到,則檢索標準目錄,不檢索當前工作目錄。
?
條件編譯命令
有幾個命令可對程序源代碼的各部分有選擇地進行編譯,該過程稱為條件編譯。商業軟件公司廣泛應用條件編譯來提供和維護某一程序的許多顧客版本。
?
#if、#else,#elif及#endif
?
#if的一般含義是如果#if后面的常量表達式為true,則編譯它與#endif之間的代碼,否則跳過這些代碼。命令#endif標識一個#if塊的結束。
?
#if constant-expression
statement sequence
#endif
?
跟在#if后面的表達式在編譯時求值,因此它必須僅含常量及已定義過的標識符,不可使用變量。表達式不許含有操作符sizeof(sizeof也是編譯時求值)。
?
#else命令的功能有點象C語言中的else;#else建立另一選擇(在#if失敗的情況下)。注意,# else屬于# if塊。
?
#elif命令意義與ELSE IF 相同,它形成一個if else-if階梯狀語句,可進行多種編譯選擇。#elif 后跟一個常量表達式。如果表達式為true,則編譯其后的代碼塊,不對其它#elif表達式進行測試。否則,順序測試下一塊。
?
#if expression
statement sequence
#elif expression1
statement sequence
#endif
?
在嵌套的條件編譯中#endif、#else或#elif與最近#if或#elif匹配。
?
# ifdef 和# ifndef
?
條件編譯的另一種方法是用#ifdef與#ifndef命令,它們分別表示"如果有定義"及"如果無定義"。# ifdef的一般形式是:
?
# ifdef macroname
statement sequence
#endif
?
#ifdef與#ifndef可以用于#if、#else,#elif語句中,但必須與一個#endif。
?
命令#undef 取消其后那個前面已定義過有宏名定義。一般形式為:
#undef macroname
?
命令# line改變__LINE__與__FILE__的內容,它們是在編譯程序中預先定義的標識符。命令的基本形式如下:
?
# line number["filename"]
?
其中的數字為任何正整數,可選的文件名為任意有效文件標識符。行號為源程序中當前行號,文件名為源文件的名字。命令# line主要用于調試及其它特殊應用。注意:在#line后面的數字標識從下一行開始的數字標識。
?
預定義的宏名
?
ANSI標準說明了C中的五個預定義的宏名。它們是:
?
__LINE__
__FILE__
__DATE__
__TIME__
__STDC__
?
如果編譯不是標準的,則可能僅支持以上宏名中的幾個,或根本不支持。記住編譯程序也許還提供其它預定義的宏名。
?
__LINE__及__FILE__宏指令在有關# line的部分中已討論,這里討論其余的宏名。
__DATE__宏指令含有形式為月/日/年的串,表示源文件被翻譯到代碼時的日期。
源代碼翻譯到目標代碼的時間作為串包含在__TIME__中。串形式為時:分:秒。
如果實現是標準的,則宏__STDC__含有十進制常量1。如果它含有任何其它數,則實現是非標準的。編譯C++程序時,編譯器自動定義了一個預處理名字__cplusplus,而編譯標準C時,自動定義名字__STDC__。
?
注意:宏名的書寫由標識符與兩邊各二條下劃線構成。
?
(部分內容出自:http://www.bc-cn.net/Article/kfyy/cyy/jc/200511/919.html) 8、
?
C、C++宏體中出現的#,#@,##
?
宏體中,#的功能是將其后面的宏參數進行字符串化操作(Stringfication),簡單說就是在對它所引用的宏變量通過替換后在其左右各加上一個雙引號。
?
而##被稱為連接符(concatenator),用來將兩個Token連接為一個Token。注意這里連接的對象是Token就行,而不一定是宏的變量。比如你要做一個菜單項命令名和函數指針組成的結構體。
http://baike.baidu.com/view/3487831.htm
#pragma comment( comment-type ,["commentstring"] )
comment-type是一個預定義的標識符,指定注釋的類型,應該是compiler,exestr,lib,linker之一。
commentstring是一個提供為comment-type提供附加信息的字符串。
注釋類型:
1、compiler:
放置編譯器的版本或者名字到一個對象文件,該選項是被linker忽略的。
2、exestr:
在以后的版本將被取消。
3、lib:
放置一個庫搜索記錄到對象文件中,這個類型應該是和commentstring(指定你要Linker搜索的lib的名稱和路徑)這個庫的名字放在Object文件的默認庫搜索記錄的后面,linker搜索這個這個庫就像你在命令行輸入這個命令一樣。你可以在一個源文件中設置多個庫記錄,它們在object文件中的順序和在源文件中的順序一樣。如果默認庫和附加庫的次序是需要區別的,使用Z編譯開關是防止默認庫放到object模塊。
4、linker:
指定一個連接選項,這樣就不用在命令行輸入或者在開發環境中設置了。
只有下面的linker選項能被傳給Linker.
/DEFAULTLIB ,/EXPORT,/INCLUDE,/MANIFESTDEPENDENCY, /MERGE,/SECTION
(1) /DEFAULTLIB:library
/DEFAULTLIB 選項將一個 library 添加到 LINK 在解析引用時搜索的庫列表。用 /DEFAULTLIB指定的庫在命令行上指定的庫之后和 .obj 文件中指定的默認庫之前被搜索。忽略所有默認庫 (/NODEFAULTLIB) 選項重寫 /DEFAULTLIB:library。如果在兩者中指定了相同的 library 名稱,忽略庫 (/NODEFAULTLIB:library) 選項將重寫 /DEFAULTLIB:library。
(2)/EXPORT:entryname[,@ordinal[,NONAME]][,DATA]
使用該選項,可以從程序導出函數,以便其他程序可以調用該函數。也可以導出數據。通常在 DLL 中定義導出。entryname 是調用程序要使用的函數或數據項的名稱。ordinal 在導出表中指定范圍在 1 至 65,535 的索引;如果沒有指定 ordinal,則 LINK 將分配一個。NONAME 關鍵字只將函數導出為序號,沒有 entryname。
DATA 關鍵字指定導出項為數據項。客戶程序中的數據項必須用 extern __declspec(dllimport) 來聲明。
有三種導出定義的方法,按照建議的使用順序依次為:
源代碼中的 __declspec(dllexport).def 文件中的 EXPORTS 語句LINK 命令中的 /EXPORT 規范所有這三種方法可以用在同一個程序中。LINK 在生成包含導出的程序時還創建導入庫,除非生成中使用了 .exp 文件。
LINK 使用標識符的修飾形式。編譯器在創建 .obj 文件時修飾標識符。如果 entryname 以其未修飾的形式指定給鏈接器(與其在源代碼中一樣),則 LINK 將試圖匹配該名稱。如果無法找到唯一的匹配名稱,則 LINK 發出錯誤信息。當需要將標識符指定給鏈接器時,請使用 Dumpbin 工具獲取該標識符的修飾名形式。
(3)/INCLUDE:symbol
/INCLUDE 選項通知鏈接器將指定的符號添加到符號表。
若要指定多個符號,請在符號名稱之間鍵入逗號 (,)、分號 (;) 或空格。在命令行上,對每個符號指定一次 /INCLUDE:symbol。
鏈接器通過將包含符號定義的對象添加到程序來解析 symbol。該功能對于添包含不會鏈接到程序的庫對象非常有用。用該選項指定符號將通過 /OPT:REF 重寫該符號的移除。
我們經常用到的是#pragma comment(lib,"*.lib")這類的。#pragma comment(lib,"Ws2_32.lib")表示鏈接Ws2_32.lib這個庫。 和在工程設置里寫上鏈入Ws2_32.lib的效果一樣,不過這種方法寫的 程序別人在使用你的代碼的時候就不用再設置工程settings了
總結
以上是生活随笔為你收集整理的c/c++标准预定义宏的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: OpenCV 2.2.0 CvvImag
- 下一篇: 解决:VS 2005/2008 中 fs