#if #elif [defined(), !defined()] #else #ifdef #ifndef #endif // 条件编译
/* 头文件防止多次被包含 */ #ifndef ZLIB_H #define ZLIB_H #endif /* ZLIB_H */ /* 用C方式来修饰函数与变量 */ #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的实现*/ 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 _UNICODE wcscpy(pszCopy, psz); #elif !defined(OLE2ANSI) MultiByteToWideChar(CP_ACP, 0, psz, -1, pszCopy, cch); #else lstrcpy(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 _UNICODE typedef wchar_t TCHAR; #define __T(x) L ## x #define _tmain wmain #define _tprintf wprintf #else typedef char TCHAR; #define __T(x) x #define _tmain main #define _tprintf printf #endif #define _TEXT(x) __T(x) #define _T(x) __T(x) /* 使用OF宏来适配函数参数 */ #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变量获得当前文件名*/ #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. ") // 注:字符串是可以用空格分开写的,编译器会将其合成一个字符串;如: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> // 只搜索系统目录 #include "stdafx.h" // 先搜索工程当前目录,再搜索系统目录 #include "../zlib/zconf.h" // 以当前文件作为参考来计算 // #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不区分""与<>,都是先搜索工程当前目录,再搜索系统目录
#line 指示下一行的行号,及当前所在的文件;该命令会修改__FILE__、__LINE__的值
该命令是提供给编译器使用的,程序员最好不要使用该命令,否则会导致调试异常(如:断点打不上等)
#line 100 "myFile.cpp" printf("File: %s, Line: %d, Function: %s ", __FILE__, __LINE__ ,__FUNCTION__); // 输出File: f:vstestvstestmyfile.cpp, Line: 101, Function: wmain
#pragma
#pragma once // 防止头文件重复包含【vc编译器版本:_MSC_VER > 1000时才支持#pragma once】 #pragma message ("发布版本请去掉测试代码") // 编译时打印自定义信息 #pragma warning(disable: 4102 4235) // 不提示C4102、C4235的warning #pragma warning(once:4385) // C4385警告仅报告一次 #pragma warning(error:164) // C164警告信息视为错误 #pragma warning(default: 4310) // 将C4310的警告行为到默认状态 #pragma warning(disable:4507 34; once:4385; error:164) #pragma warning(push) //保存现有警告状态 #pragma warning(push, 3) //保存现有警告状态,并且把warning level设为3 #pragma warning(pop) //弹出栈顶的一个警告信息,这对导致push和pop之间所作的一切改动取消掉 #pragma comment(lib, "../zlib/zlib.lib") // 链入zlib.lib导出库 // 目录结构如下: +-- testStdafx.h |- Debug +-- testLib.lib #pragma comment(lib, __FILE__ "\..\" "Debug\" "testLib.lib") // 若当前文件为testStdafx.h,在testStdafx.h中包含自己的lib文件,可以避免外部工程手动包含test.lib // 外部工程只需要#include "testStdafx.h"即可,如果多个工程使用testLib.lib,这个做法非常方便 // 后面路径分段个数没有限制,理论上任意多个都行 /*#pragma data_seg指定函数存放在*.obj文件中的数据段,默认的代码段是.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指定函数存放在*.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中;共享数据必须初始化,否则会放到.BSS段中 #pragma data_seg("shareddata") int nTotalNum = 0; //nTotalNum可以被多个进程共享 #pragma data_seg() /* #pragma comment(linker,...)主要用来设置链接参数 */ /* 常见的链接参数详见: */ /* http://www.cnblogs.com/kekec/archive/2013/04/21/3007277.html中的Link.exe段的说明 */ // 将flag_data数据段设置为可读、可写、可共享 #pragma comment(linker,"/SECTION:flag_data,RWS") // 导出extern "C" fnSub函数 #pragma comment (linker, "/EXPORT:_fnSub") // 导出extern "C" fnAdd函数,并将符号名修改为myfnAdd,同时将导出序号设为1 #pragma comment (linker, "/EXPORT:myfnAdd=_fnAdd,@1") // 强制包含名为__mySymbol的符号; // 若要指定多个符号,请在符号名称之间键入逗号、分号或空格 #pragma comment(linker, "/include:__mySymbol") /* 区别:源码的inline在编译器进行预处理的时候就展开了,*/ /* 而#Pragma intrinsic却是以二进制的方式inline进去的 */ // 使用内联版本的memset及strlen #pragma intrinsic(memset, strlen) /* 使用回函数调用的strlen */ #pragma function(strlen) /* 对于不同文件中的全局对象、变量,它们的构造函数调用顺序是未定义的,取决于具体的编译器,这就可能带来一些问题 */ /* compiler、lib、user,初始化优先次序依次降低,但都先于普通的全局变量构造*/ /* 对于必须优先被初始化的对象或变量应使用这3个指令 */ /* 一个源文件只能出现一次init_seg 指令 */ #pragma init_seg(compiler) #pragma init_seg(lib) #pragma init_seg(user) #pragma init_seg("user_defined_segment_name") // 用户自定义名称 // 内存对齐 // 详见:http://www.cnblogs.com/kekec/archive/2012/10/31/2748955.html #pragma pack(push, 4) #pragma pack(pop) #pragma optimize("", off) // 关闭代码编译优化 #pragma optimize("", on) // 开启代码编译优化 #pragma inline_recursion(on) // 开启内联递归 #pragma inline_recursion(off) // 关闭内联递归 // 函数堆栈深度超过指定深度,就不进行函数内联 #pragma inline_depth(0) // 不进行任何内联 #pragma inline_depth(10) // 深度超过10层,不进行函数内联 #pragma inline_depth() // 缺省深度值为254 // myheader.h关闭最小重新生成【见/Gm编译选项】 /* myheader.h起始处 */ #pragma component(minrebuild, off) /* myheader.h */ #pragma component(minrebuild, on) /* myheader.h结束处 */
#error // c编译器error命令
#ifndef __cplusplus #error MFC requires C++ compilation (use a .cpp suffix) #endif extern "C" { #error "printf error!" };
__VA_ARGS__ 【变参】 新的C99规范中增加的,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 ", a, chs); // printf("%d %s ", a, chs); debug2("%d %s ", a, chs); // printf("%d %s ", a, chs); debug3("%d %s ", a, chs); // printf("%d %s ",a, chs); a前会少一个空格 /* 安全调用对象的方法 */ #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__前加上##的作用在于,当可变参数的个数为0时,将##前面多余的逗号去掉,否则会编译不过(vs不加##,也可以编译过)
__FILE__、__LINE__、__FUNCTION__、__DATE__、__TIME__、__TIMESTAMP__
// File: f:vsconsole1vsconsole1vsconsole1.cpp, Line: 9, Function: wmain // vc6不支持__FUNCTION__宏 printf("File: %s, Line: %d, Function: %s ",__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 ",__DATE__,__TIME__, __TIMESTAMP__);
注:__DATE__、__TIME__、__TIMESTAMP__会被替换成该源文件编译成obj文件时的日期、时间、和unix时间戳
__STDC__、__STDC_VERSION__、__cplusplus
__STDC__ // 当前编译器符合c标准,则该宏的值为1 __STDC_VERSION__ // 当前编译器符合C89, 该宏的值为199409L, 符合C99, 该宏的值为199901L __cplusplus // 当前编译器符合c++标准,则该宏值为编译器版本号 // 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
Product name | Codename | Internal version | Supported .NET Framework versions | Release date |
---|---|---|---|---|
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 |
Visual Studio 2015 | Dev14 | 14.0 | 2.0 - 4.6.1 | 2015-07-20 |
Visual Studio 2017 | Dev15 | 15.0 | 3.5 - 4.7.2 | 2017-03-07 |
Visual Studio 2019 | Dev16 | 16.0 | 3.5 - 4.8 | 2019-04-02 |
WINVER
win32具有良好的向下兼容性,低版本的win32程序可以在后续高版本的windows系统上正确运行
随着windows版本的升级,更多Windows API被加入,为了能在程序中使用这些新增的API函数,可以将WINVER宏设定到更高的版本,保证程序能编译链接到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 |
编译时打印出宏的内容
//测试宏 #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) //编译时打印出宏的内容 #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)