预编译指令与宏定义
#if ?#elif [defined(), !defined()] ?#else? ? #ifdef ? #ifndef ? ??#endif ? // 條件編譯
/* 頭文件防止多次被包含 */ #ifndef ZLIB_H #define ZLIB_H#endif /* ZLIB_H *//* 用C方式來修飾函數(shù)與變量 */ #ifdef __cplusplus extern "C" { #endif int add(int a, int b); int g_nVal = 0; #ifdef __cplusplus } #endif/* 條件嵌套 */ #ifdef __STDC_VERSION__ # ifndef STDC # define STDC # endif # if __STDC_VERSION__ >= 199901L # endif # if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) # define STDC # endif #endif/* 日志輸出 */ #if defined( DEBUG ) && defined( _MSC_VER ) # include <windows.h> # define PRINT_LOG OutputDebugString #else # define PRINT_LOG printf #endif/* MFC中_AfxCopyString的實現(xiàn)*/ inline LPOLESTR AFXAPI _AfxCopyString(LPCTSTR psz) {if (psz == NULL)return NULL;int cch = lstrlen(psz) + 1;LPOLESTR pszCopy = NULL;if ((pszCopy = (LPOLESTR)CoTaskMemAlloc(cch * sizeof(OLECHAR))) != NULL){ #ifdef _UNICODEwcscpy(pszCopy, psz); #elif !defined(OLE2ANSI)MultiByteToWideChar(CP_ACP, 0, psz, -1, pszCopy, cch); #elselstrcpy(pszCopy, psz); #endif}return pszCopy; }?
#define ?#undef ? ? // 宏定義、宏取消
#define FAR #define _DEBUG #define MAX_PATH 260 #define NULL ((void *)0) #define PASCAL __stdcall #define CALLBACK FAR PASCAL #define DEBUG_NEW new #define new DEBUG_NEW #define _PUC unsigned char * #define _CPUC const unsigned char * #define _PC char * #define _CPC const char * #define _UI unsigned int #define MAX(a,b) (((a) > (b)) ? (a) : (b)) #define TRACE ::AfxTrace #define TRACE0(sz) ::AfxTrace(_T("%s"), _T(sz)) #define TRACE1(sz, p1) ::AfxTrace(_T(sz), p1) #define TRACE2(sz, p1, p2) ::AfxTrace(_T(sz), p1, p2) #define TRACE3(sz, p1, p2, p3) ::AfxTrace(_T(sz), p1, p2, p3)// 重新定義FALSE、TRUE、NULL #undef FALSE #undef TRUE #undef NULL #define FALSE 0 #define TRUE 1 #define NULL 0/* TCHAR.H */ #ifdef _UNICODEtypedef wchar_t TCHAR;#define __T(x) L ## x#define _tmain wmain#define _tprintf wprintf #elsetypedef char TCHAR;#define __T(x) x#define _tmain main#define _tprintf printf #endif #define _TEXT(x) __T(x) #define _T(x) __T(x)/* 使用OF宏來適配函數(shù)參數(shù) */ #ifndef OF # ifdef STDC # define OF(args) args # else # define OF(args) () # endif #endif int add OF((int a, int b));/* 宏必須在一行寫完,多行寫時必須帶上 \行連接符 */ /* 注意##字符拼接符 */ #define DECLARE_DYNAMIC(class_name) \ public: \static const AFX_DATA CRuntimeClass class##class_name; \virtual CRuntimeClass* GetRuntimeClass() const;/* Debug時可使用THIS_FILE變量獲得當(dāng)前文件名*/ #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif?
## ?# ?#@ ?// 特殊符號
/* ## 字符拼接符 */ #define Conn(x,y) x ## y int n = Conn(123,456); //n = 123456; char* str = Conn("abc","def"); //str = "abcdef";/* # 加雙引號 */ #define ToString(x) #x #define PrintAge(age) printf("I am " #age " years old.\n") // 注:字符串是可以用空格分開寫的,編譯器會將其合成一個字符串;如:printf("Hello " "World" "!")等價于printf("Hello World!") char* str = ToString(12.345); //str= "12.345" PrintAge(20); // 輸出 I am 20 years old./* #@ 加單引號 */ #define ToChar(x) #@x char ch = ToChar(a); //ch='a'?
#include ?#include_next【GNU的一個擴展,gcc下可使用】 ?// 文件包含
#include <stdio.h> // 只搜索系統(tǒng)目錄 #include "stdafx.h" // 先搜索工程當(dāng)前目錄,再搜索系統(tǒng)目錄 #include "../zlib/zconf.h" // 以當(dāng)前文件作為參考來計算// #include_next為GNU的一個擴展,gcc下可使用 // #include_next <xx.h> 包含在搜索路徑列表中第2次找到的xx.h // 例如:搜索路徑順序為:/usr/local/include,/usr/include // 如果這兩個目錄下都有signal.h文件,將引用/usr/include中的那個 #include_next <signal.h> // 另外#include_next不區(qū)分""與<>,都是先搜索工程當(dāng)前目錄,再搜索系統(tǒng)目錄?
#line ?指示下一行的行號,及當(dāng)前所在的文件;該命令會修改__FILE__、__LINE__的值
該命令是提供給編譯器使用的,程序員最好不要使用該命令,否則會導(dǎo)致調(diào)試異常(如:斷點打不上等)
#line 100 "myFile.cpp"printf("File: %s, Line: %d, Function: %s\n", __FILE__, __LINE__ ,__FUNCTION__); // 輸出File: f:\vstest\vstest\myfile.cpp, Line: 101, Function: wmain?
#pragma
#pragma once // 防止頭文件重復(fù)包含【vc編譯器版本:_MSC_VER > 1000時才支持#pragma once】 #pragma message ("發(fā)布版本請去掉測試代碼") // 編譯時打印自定義信息 #pragma warning(disable: 4102 4235) // 不提示C4102、C4235的warning #pragma warning(once:4385) // C4385警告僅報告一次 #pragma warning(error:164) // C164警告信息視為錯誤 #pragma warning(default: 4310) // 將C4310的警告行為到默認狀態(tài) #pragma warning(disable:4507 34; once:4385; error:164) #pragma warning(push) //保存現(xiàn)有警告狀態(tài) #pragma warning(push, 3) //保存現(xiàn)有警告狀態(tài),并且把warning level設(shè)為3 #pragma warning(pop) //彈出棧頂?shù)囊粋€警告信息,這對導(dǎo)致push和pop之間所作的一切改動取消掉#pragma comment(lib, "../zlib/zlib.lib") // 鏈入zlib.lib導(dǎo)出庫// 目錄結(jié)構(gòu)如下: +-- testStdafx.h|- Debug+-- testLib.lib #pragma comment(lib, __FILE__ "\\..\\" "Debug\\" "testLib.lib") // 若當(dāng)前文件為testStdafx.h,在testStdafx.h中包含自己的lib文件,可以避免外部工程手動包含test.lib// 外部工程只需要#include "testStdafx.h"即可,如果多個工程使用testLib.lib,這個做法非常方便// 后面路徑分段個數(shù)沒有限制,理論上任意多個都行/*#pragma data_seg指定函數(shù)存放在*.obj文件中的數(shù)據(jù)段,默認的代碼段是.data*/ int i = 0; // 存放在"data"段 #pragma data_seg(".my_data1") int j = 1; // 存放在"my_data1"段 #pragma data_seg(push, stack1, ".my_data2") int k = 2; // 存放在"my_data2"段 #pragma data_seg(pop, stack1) // pop stack1 off the stack int m = 3; // 存放在"my_data1"段 #pragma data_seg() int n = 4; // 存放在"data"段/*#pragma code_seg指定函數(shù)存放在*.obj文件中的代碼段,默認的代碼段是.text*/ void func1() {} // 存放在text段 #pragma code_seg(".my_data1") void func2() {} // 存放在my_data1段 #pragma code_seg(push, r1, ".my_data2") void func3() {} // 存放在my_data2段 #pragma code_seg(pop, r1) void func4() {} // 存放在my_data1段 #pragma code_seg() void func5() {} // 存放在text段/* 除了data_seg和code_seg之外,還有bss_seg與const_seg */ /* bss_seg與const_seg的使用與data_seg、code_seg一致*///shareddata 一般用于dll中;共享數(shù)據(jù)必須初始化,否則會放到.BSS段中 #pragma data_seg("shareddata") int nTotalNum = 0; //nTotalNum可以被多個進程共享 #pragma data_seg()/* #pragma comment(linker,...)主要用來設(shè)置鏈接參數(shù) */ /* 常見的鏈接參數(shù)詳見: */ /* http://www.cnblogs.com/kekec/archive/2013/04/21/3007277.html中的Link.exe段的說明 */// 將flag_data數(shù)據(jù)段設(shè)置為可讀、可寫、可共享 #pragma comment(linker,"/SECTION:flag_data,RWS")// 導(dǎo)出extern "C" fnSub函數(shù) #pragma comment (linker, "/EXPORT:_fnSub") // 導(dǎo)出extern "C" fnAdd函數(shù),并將符號名修改為myfnAdd,同時將導(dǎo)出序號設(shè)為1 #pragma comment (linker, "/EXPORT:myfnAdd=_fnAdd,@1")// 強制包含名為__mySymbol的符號; // 若要指定多個符號,請在符號名稱之間鍵入逗號、分號或空格 #pragma comment(linker, "/include:__mySymbol")/* 區(qū)別:源碼的inline在編譯器進行預(yù)處理的時候就展開了,*/ /* 而#Pragma intrinsic卻是以二進制的方式inline進去的 */ // 使用內(nèi)聯(lián)版本的memset及strlen #pragma intrinsic(memset, strlen)/* 使用回函數(shù)調(diào)用的strlen */ #pragma function(strlen)/* 對于不同文件中的全局對象、變量,它們的構(gòu)造函數(shù)調(diào)用順序是未定義的,取決于具體的編譯器,這就可能帶來一些問題 */ /* compiler、lib、user,初始化優(yōu)先次序依次降低,但都先于普通的全局變量構(gòu)造*/ /* 對于必須優(yōu)先被初始化的對象或變量應(yīng)使用這3個指令 */ /* 一個源文件只能出現(xiàn)一次init_seg 指令 */ #pragma init_seg(compiler) #pragma init_seg(lib) #pragma init_seg(user) #pragma init_seg("user_defined_segment_name") // 用戶自定義名稱// 內(nèi)存對齊 // 詳見:http://www.cnblogs.com/kekec/archive/2012/10/31/2748955.html #pragma pack(push, 4) #pragma pack(pop)#pragma optimize("", off) // 關(guān)閉代碼編譯優(yōu)化 #pragma optimize("", on) // 開啟代碼編譯優(yōu)化#pragma inline_recursion(on) // 開啟內(nèi)聯(lián)遞歸 #pragma inline_recursion(off) // 關(guān)閉內(nèi)聯(lián)遞歸// 函數(shù)堆棧深度超過指定深度,就不進行函數(shù)內(nèi)聯(lián) #pragma inline_depth(0) // 不進行任何內(nèi)聯(lián) #pragma inline_depth(10) // 深度超過10層,不進行函數(shù)內(nèi)聯(lián) #pragma inline_depth() // 缺省深度值為254// myheader.h關(guān)閉最小重新生成【見/Gm編譯選項】 /* myheader.h起始處 */ #pragma component(minrebuild, off) /* myheader.h */ #pragma component(minrebuild, on) /* myheader.h結(jié)束處 */?
?
#error ?// c編譯器error命令
#ifndef __cplusplus#error MFC requires C++ compilation (use a .cpp suffix) #endifextern "C" {#error "printf error!" };?
__VA_ARGS__ ?【變參】 ?新的C99規(guī)范中增加的,gcc及vs2005版本以上的ms編譯器支持該宏
/* vs2008測試 */ #define debug1(...) printf(__VA_ARGS__) #define debug2(fmt, ...) printf(fmt, __VA_ARGS__) #define debug3(fmt, ...) printf(fmt, ## __VA_ARGS__)int a = 10; const char* chs = "Hello"; debug1("%d %s\n", a, chs); // printf("%d %s\n", a, chs); debug2("%d %s\n", a, chs); // printf("%d %s\n", a, chs); debug3("%d %s\n", a, chs); // printf("%d %s\n",a, chs); a前會少一個空格/* 安全調(diào)用對象的方法 */ #define SafeCallFunc(ptr, retType, func, ...) ( (ptr!=NULL)?(ptr->func(__VA_ARGS__)):(retType(0)) ) /* 安全獲取對象的成員變量 */ #define SafeGetValue(ptr, val, valType) ( (ptr!=NULL)?(ptr->val):(valType(0)) )注:__VA_ARGS__前加上##的作用在于,當(dāng)可變參數(shù)的個數(shù)為0時,將##前面多余的逗號去掉,否則會編譯不過(vs不加##,也可以編譯過)
?
__FILE__、__LINE__、__FUNCTION__、__DATE__、__TIME__、__TIMESTAMP__
// File: f:\vsconsole1\vsconsole1\vsconsole1.cpp, Line: 9, Function: wmain // vc6不支持__FUNCTION__宏 printf("File: %s, Line: %d, Function: %s\n",__FILE__,__LINE__,__FUNCTION__); // Date: Sep 19 2013 Time: 22:38:51 TimeStamp: Thu Sep 19 22:38:50 2013 printf("Date: %s Time: %s TimeStamp: %s\n",__DATE__,__TIME__, __TIMESTAMP__);?注:__DATE__、__TIME__、__TIMESTAMP__會被替換成該源文件編譯成obj文件時的日期、時間、和unix時間戳
?
?__STDC__、__STDC_VERSION__、__cplusplus
__STDC__ // 當(dāng)前編譯器符合c標(biāo)準(zhǔn),則該宏的值為1 __STDC_VERSION__ // 當(dāng)前編譯器符合C89, 該宏的值為199409L, 符合C99, 該宏的值為199901L __cplusplus // 當(dāng)前編譯器符合c++標(biāo)準(zhǔn),則該宏值為編譯器版本號// C++ pre-C++98: __cplusplus is 1// C++98: __cplusplus is 199711L// C++98 + TR1: This reads as C++98 and there is no way to check that I know of// C++11: __cplusplus is 201103L// C++14: __cplusplus is 201402L?
_MSC_VER
_MSC_VER = 1800 // MS VC++ 12.0 _MSC_VER = 1700 // MS VC++ 11.0 _MSC_VER = 1600 // MS VC++ 10.0 _MSC_VER = 1500 // MS VC++ 9.0 _MSC_VER = 1400 // MS VC++ 8.0 _MSC_VER = 1310 // MS VC++ 7.1 _MSC_VER = 1300 // MS VC++ 7.0 _MSC_VER = 1200 // MS VC++ 6.0 _MSC_VER = 1100 // MS VC++ 5.0?
參考:http://en.wikipedia.org/wiki/Microsoft_Visual_Studio
| Visual Studio | N/A | 4.0 | N/A | April 1995 |
| Visual Studio 97 | Boston | 5.0 | N/A | February 1997 |
| Visual Studio 6.0 | Aspen | 6.0 | N/A | June 1998 |
| Visual Studio .NET (2002) | Rainier | 7.0 | 1.0 | February 13, 2002 |
| Visual Studio .NET 2003 | Everett | 7.1 | 1.1 | April 24, 2003 |
| Visual Studio 2005 | Whidbey | 8.0 | 2.0, 3.0 | November 7, 2005 |
| Visual Studio 2008 | Orcas | 9.0 | 2.0, 3.0, 3.5 | November 19, 2007 |
| Visual Studio 2010 | Dev10/Rosario | 10.0 | 2.0, 3.0, 3.5, 4.0 | April 12, 2010 |
| Visual Studio 2012 | Dev11 | 11.0 | 2.0, 3.0, 3.5, 4.0, 4.5, 4.5.1, 4.5.2 | September 12, 2012 |
| Visual Studio 2013 | Dev12 | 12.0 | 2.0, 3.0, 3.5, 4.0, 4.5, 4.5.1, 4.5.2 | October 17, 2013 |
?
WINVER
win32具有良好的向下兼容性,低版本的win32程序可以在后續(xù)高版本的windows系統(tǒng)上正確運行
隨著windows版本的升級,更多Windows API被加入,為了能在程序中使用這些新增的API函數(shù),可以將WINVER宏設(shè)定到更高的版本,保證程序能編譯鏈接到windows SDK中的這些API;
但與此同時,也帶來了新的問題,意味著你的程序只能在更高版本的windows上運行
How to modify WINVER? ? ?Using the Windows Headers
參考:https://en.wikipedia.org/wiki/List_of_Microsoft_Windows_versions
? ? ? ??https://en.wikipedia.org/wiki/Comparison_of_Microsoft_Windows_versions
| Name | Release version | WINVER | Architecture |
| Windows NT 4.0 | NT 4.0 | ?0x0400 | IA-32,?DEC Alpha,MIPS,?PowerPC |
| Windows 2000 | NT 5.0 | ?0x0500 | IA-32,?IA-64 |
| Windows XP | NT 5.1; NT 5.2 (64-bit2003 and x64) | ?0x0501 ?0x0502 | IA-32,?IA-64,?x86-64 |
| Windows Server 2003 | NT 5.2 | ?0x0502 | IA-32,?IA-64,?x86-64 |
| Windows Vista | NT 6.0 | ?0x0600 | IA-32,?x86-64 |
| Windows Server 2008 | NT 6.0 | ?0x0600 | IA-32,?IA-64,?x86-64 |
| Windows 7 | NT 6.1 | ?0x0601 | IA-32,?x86-64 |
| Windows 8 | NT 6.2 | ?0x0602 | IA-32,?x86-64,?ARM architecture?(ARMv7) |
| Windows 8.1 | NT 6.3 | ?0x0603 | IA-32,?x86-64,?ARM architecture?(ARMv7) |
| Windows 10 | NT 10.0 | ?0x0A00 | ? |
?
編譯時打印出宏的內(nèi)容
//測試宏 #define PI 3.1415926 #define MAX(a,b) (a)>(b) ? (a) :(b)//首先定義兩個輔助宏 #define?? PRINT_MACRO_HELPER(x)?? #x? #define?? PRINT_MACRO(x)?? #x"="PRINT_MACRO_HELPER(x)?//編譯時打印出宏的內(nèi)容 #pragma message(PRINT_MACRO(PI)) // PI=3.1415926 #pragma message(PRINT_MACRO(PI2)) // PI2=PI2 注:PI2沒定義 #pragma message(PRINT_MACRO(MAX(a,b)))// MAX(a,b)=(a)>(b) ? (a) :(b) #pragma message(PRINT_MACRO(MAX(x,y))) // MAX(x,y)=(x)>(y) ? (x) :(y)?
轉(zhuǎn)載于:https://www.cnblogs.com/kekec/p/3304224.html
總結(jié)
- 上一篇: 关于Jenkins找不到依赖Jar包问题
- 下一篇: 一个经典的对象级别插件的开发