预编译指令与宏定义

#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.\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_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\n", __FILE__, __LINE__ ,__FUNCTION__); 
// 输出File: f:\vstest\vstest\myfile.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\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前会少一个空格

/* 安全调用对象的方法 */
#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:\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__  // 当前编译器符合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 StudioN/A4.0N/AApril 1995
Visual Studio 97Boston5.0N/AFebruary 1997
Visual Studio 6.0Aspen6.0N/AJune 1998
Visual Studio .NET (2002)Rainier7.01.0February 13, 2002
Visual Studio .NET 2003Everett7.11.1April 24, 2003
Visual Studio 2005Whidbey8.02.0, 3.0November 7, 2005
Visual Studio 2008Orcas9.02.0, 3.0, 3.5November 19, 2007
Visual Studio 2010Dev10/Rosario10.02.0, 3.0, 3.5, 4.0April 12, 2010
Visual Studio 2012Dev1111.02.0, 3.0, 3.5, 4.0, 4.5, 4.5.1, 4.5.2September 12, 2012
Visual Studio 2013Dev1212.02.0, 3.0, 3.5, 4.0, 4.5, 4.5.1, 4.5.2October 17, 2013

 

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

NameRelease
version
WINVER

Architecture

Windows NT 4.0NT 4.0 0x0400IA-32DEC Alpha,MIPSPowerPC
Windows 2000NT 5.0 0x0500IA-32IA-64
Windows XPNT 5.1; NT 5.2
(64-bit2003 and x64)

 0x0501

 0x0502

IA-32IA-64x86-64
Windows Server 2003NT 5.2 0x0502IA-32IA-64x86-64
Windows VistaNT 6.0 0x0600IA-32x86-64
Windows Server 2008NT 6.0 0x0600IA-32IA-64x86-64
Windows 7NT 6.1 0x0601IA-32x86-64
Windows 8NT 6.2 0x0602IA-32x86-64ARM architecture (ARMv7)
Windows 8.1NT 6.3 0x0603IA-32x86-64ARM architecture (ARMv7)
Windows 10NT 10.0 0x0A00 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值