预编译指令与宏定义

#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_nextGNU的一个扩展,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 nameCodenameInternal
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-32DEC Alpha,MIPSPowerPC
Windows 2000 NT 5.0  0x0500 IA-32IA-64
Windows XP NT 5.1; NT 5.2
(64-bit2003 and x64)

 0x0501

 0x0502

IA-32IA-64x86-64
Windows Server 2003 NT 5.2  0x0502 IA-32IA-64x86-64
Windows Vista NT 6.0  0x0600 IA-32x86-64
Windows Server 2008 NT 6.0  0x0600 IA-32IA-64x86-64
Windows 7 NT 6.1  0x0601 IA-32x86-64
Windows 8 NT 6.2  0x0602 IA-32x86-64ARM architecture (ARMv7)
Windows 8.1 NT 6.3  0x0603 IA-32x86-64ARM 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)

原文地址:https://www.cnblogs.com/kekec/p/3304224.html