VC 宏与预处理使用方法总结(转)


目录(?) [-]
  1. C/C++ 预定义宏^
    1. C/C++ 预定义宏用途:诊断与调试输出^
  2. CRT 和 C 标准库中的宏^
    1. NULL 空指针^
    2. limits.h 整数类型常量^
    3. float.h 浮点类型常量^
    4. math.h 数学常量^
    5. EOF 常量^
    6. errno.h 错误代码^
    7. locale 类别^
    8. _MAX_PATH 等文件名与路径长度限制^
    9. RAND_MAX 随机数最大值^
    10. va_arg/va_start/va_end 访问变长函数参数^
    11. 宏实现的 CRT 函数^
  3. Microsoft 预定义宏^
    1. 平台与系统类^
    2. 版本号类^
    3. 工程配置管理类^
    4. 辅助类^
  4. Windows API 中的注释性宏^
  5. Windows API 中的常用宏^
    1. 类型辅助类^
    2. GDI 类^
    3. 错误处理类^
    4. 调用规范类^
    5. 国际化类^
    6. 资源类^
    7. 网络类^
  6. 字符串化操作符 #^
    1. 用 # 操作构造字符串化宏 STRINGIZE^
    2. CRT 中的 STRINGIZE 定义^
    3. STRINGIZE 的展开规则^
  7. 拼接操作符 ##^
  8. TCHAR 统一字符类型和处理^
    1. _TCHAR, _TEXT()/_T(), _t 系列函数^
    2. TCHAR, LPTSTR/LPCTSTR, TEXT(), A/W 版本 Windows API^
  9. 宏的缺点和替代方法^
    1. 宏难于调试^
    2. 宏的使用缺陷^
    3. 宏造成全局名字空间污染^
    4. 优先使用宏的情况^
  10. 条件编译^
  11. 预编译头文件^
    1. 使用 PCH 的编译命令^
  12. 常用预处理指令^
    1. #error 产生人工编译错误^
    2. #line 改变行号和源文件名^
    3. # 空指令^
  13. #pragma 预处理指令^
    1. #pragma once 只包含一次头文件^
    2. #pragma message 编译时输出消息^
    3. #pragma push_macro/pop_macro 保存和恢复宏定义^
    4. #pragma warning 禁用和启用编译警告^
    5. #pragma comment 目标文件注释和编译选项传递^
    6. #pragma 区段操作^
    7. #pragma pack 设置成员字节对齐^
    8. #pragma inline 函数设置^
    9. #pragma 优化指令^
    10. #pragma deprecated 声明废弃函数^
    11. #pragma omp 使用 OpenMP 指令^
    12. #pragma region/endregion 折叠代码块^
    13. #pragma setlocale 设置源代码中字符串字面量的编码^
    14. #pragma include_alias 定义头文件别名^
  14. 预处理相关编译选项^
    1. /D 定义宏^
    2. /E, /EP, /P 预处理选项^
    3. /showIncludes 输出头文件列表^

作者:Breaker Zhao
转载请注明作者和原文链接

VC 2005 中的宏 (#define) 与预处理 (#if/#ifdef/#pragma) 的使用方法总结。

关键字:宏, 预定义宏, 预处理, 预编译头, VC, #pragma, 编译选项, 程序区段

目录


VC 中的宏使用方法参考 MSDN: Macros (C/C++)

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">C/C++ 预定义宏^

__LINE__: 当前源文件的行号,整数
__FILE__: 当前源文件名,char 字符串,使用 /FC 选项产生全路径
__DATE__: 当前编译日期,char 字符串,格式 Aug 28 2011
__TIME__: 当前编译时间,char 字符串,格式 06:43:59
__STDC__: 整数 1,表示兼容 ANSI/ISO C 标准,配合 #if 使用
__TIMESTAMP__: 最后一次修改当前文件的时间戳,char 字符串,格式 Sun Aug 28 06:43:57 2011
__cplusplus: 以 C++ 方式而非 C 语言方式编译时定义,VC 2005 中定义为 199711L,配合 #ifdef 使用

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">例子:C/C++ 预定义宏的取值^

  1. // assert.h  
  2.   
  3. _CRTIMP void __cdecl _wassert(__in_z const wchar_t * _Message, __in_z const wchar_t *_File, __in unsigned _Line);  
  4.   
  5. #define assert(_Expression) (void)( (!!(_Expression)) || (_wassert(_CRT_WIDE(#_Expression), _CRT_WIDE(__FILE__), __LINE__), 0) )  
  6.   
  7. // crtdbg.h  
  8.   
  9. #define _ASSERT_EXPR(expr, msg) \  
  10.         (void) ((!!(expr)) || \  
  11.                 (1 != _CrtDbgReportW(_CRT_ASSERT, _CRT_WIDE(__FILE__), __LINE__, NULL, msg)) || \  
  12.                 (_CrtDbgBreak(), 0))  
  13.   
  14. #ifndef _ASSERT  
  15. #define _ASSERT(expr)   _ASSERT_EXPR((expr), NULL)  
  16. #endif  
  17.   
  18. #ifndef _ASSERTE  
  19. #define _ASSERTE(expr)  _ASSERT_EXPR((expr), _CRT_WIDE(#expr))  
  20. #endif  

CRT 的调试输出宏 _RPTn()/_RPTFn(),n: 0 ~ 5
_RPTWn()/_RPTFWn() 是宽字符版

  1. // afx.h  
  2.   
  3. #define ASSERT(f)          DEBUG_ONLY((void) ((f) || !::AfxAssertFailedLine(THIS_FILE, __LINE__) || (AfxDebugBreak(), 0)))  
  4. #define ASSERT_VALID(pOb)  DEBUG_ONLY((::AfxAssertValidObject(pOb, THIS_FILE, __LINE__)))  

MFC 的调试输出宏 TRACE()/TRACEn(),n: 0 ~ 3

  1. // afx.h  
  2.   
  3. void* AFX_CDECL operator new(size_t nSize, LPCSTR lpszFileName, int nLine);  
  4. #define DEBUG_NEW new(THIS_FILE, __LINE__)  
  5.   
  6. // 用户代码  
  7.   
  8. // 调试版 new  
  9. #ifdef _DEBUG  
  10. #define new DEBUG_NEW  
  11. #endif  

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">CRT 和 C 标准库中的宏^

VC CRT 和 C 标准库中的宏参考 MSDN: Global Constants

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">NULL 空指针^

NULL 在 stddef.h, stdio.h, stdlib.h 等多个头文件中定义,是地址/指针类型的 0,如下:

  1. // baby pointer wrapper  
  2. class Pointer  
  3. {  
  4. public:  
  5.     // 非 explicit 构造函数,说明 Pointer 可以从指针类型 void* 隐式转换  
  6.     Pointer(void* p) : m_Ptr(p)  
  7.     {}  
  8.   
  9.     bool IsNull() const  
  10.     {  
  11.         return (m_Ptr == NULL);  
  12.     }  
  13.   
  14. private:  
  15.     void*    m_Ptr;  
  16. };  
  17.   
  18. // 形参可以从指针类型 void* 隐式转换  
  19. void TestPointer(Pointer ptr)  
  20. {  
  21.     _tprintf(_T("ptr is %sNULL\n"), ptr.IsNull() ? _T("") : _T("NOT "));  
  22. }  
  23.   
  24. // 用户代码  
  25. TestPointer(0);         // OK,0 是类型自动的,0 被自动转换为 void*,再次隐式转换为 Pointer  
  26. TestPointer(NULL);      // OK,NULL 就是 0,同上  
  27. TestPointer(1);         // Error,C++ 中 1 不同于 0,它是确定的 int 类型,  
  28.                         // 只能提升转换到 float/double 类型,不能自动转换为指针  
  29. TestPointer((int*)1);   // OK,强制转换 1 为 int*,int* 自动转换为 void*,再次隐式转换为 Pointer  
  30.                         // 注意:void* 到 int* 不能自动转换,需要强制,参考 malloc() 的返回值  
" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">limits.h 整数类型常量^

在 limits.h 中定义,定义了各种 int 类型 (unsigned, char, short, long, __int64) 的最小、最大值,如 SCHAR_MAX (signed char MAX)、UCHAR_MAX (unsigned char MAX)、USHRT_MAX (unsigned short MAX) 等。编译时,如果 int 字面量超出这些范围,会编译出错

参考 MSDN: Integer Limits

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">float.h 浮点类型常量^

在 float.h 中定义,定义各种浮点类型 (float, double, long double) 的极限值,如最小、最大值,最小浮点差量 (epsilon) 等

参考 MSDN: Floating Limits

例子:浮点数极限值:判断浮点数是否相等^

  1. #define _USE_MATH_DEFINES  
  2. #include <math.h>  
" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">EOF 常量^

EOF (end-of-file) 常量,定义为 (-1),有宽字符版 WEOF ((wint_t)(0xFFFF)),EOF 和 WEOF 在 stdio.h 中定义,还有 _TCHAR 版 _TEOF,在 tchar.h 中定义。EOF 在流、I/O 操作中表示到达流、文件末尾(EOF 条件),也用来表示发生错误情况

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">例子:标准输入的 EOF^

  1. abc汉字  
  2. [a][b][/c][汉][字][  
  3. ]^Z  
  4.   
  5. read stdin: EOF  
" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">errno.h 错误代码^

在 errno.h 中定义,是测试全局量 errno 的值,errno 在 VC 中实现为线程安全的函数,而非全局变量。错误代码以 E 打头如 EINVAL:不合法的参数错误

错误代码具体值参考 MSDN: errno Constants 和 errno, _doserrno, _sys_errlist, and _sys_nerr

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">locale 类别^

locale 类别 (Categories),在 locale.h 中定义,如 LC_ALL、LC_CTYPE

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">_MAX_PATH 等文件名与路径长度限制^

包括全路径与各部分路径的限制,即 FILENAME_MAX、_MAX_PATH、_MAX_DRIVE、_MAX_EXT、_MAX_FNAME、_MAX_DIR,在 stdlib.h 中定义。最大全路径长度限制在 260,和 Windows 的 MAX_PATH 相同,这是为了兼容 Windows 98 FAT32 文件系统。CRT 支持 32767 长度的文件名,方法和 Windows API 相同,即使用 "\\?\" 路径前缀,并调用 Unicode 宽字符版的 CRT 函数

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">RAND_MAX 随机数最大值^

在 stdlib.h 中定义为 32767,rand() 函数会产生 0 ~ RAND_MAX 之间的伪随机 int 值

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">例子:用 RAND_MAX 产生某个范围内的随机数^

  1. // 针对参数不为 void,且需要保存返回值的函数  
  2. #define CALL_TRACE(func, ret, ...)      { _tprintf(_T("call: %s\n"), _TSTRINGIZE(func)); ret = func(__VA_ARGS__); }  
  3. // 针对返回值为 void 或不关心返回值的函数  
  4. #define CALL_TRACE_VOID(func, ...)      { _tprintf(_T("call: %s\n"), _TSTRINGIZE(func)); func(__VA_ARGS__); }  
  5.   
  6. // 针对参数为 void 的函数  
  7. // NOTE: 函数 func() 使用 func(__VA_ARGS__) 展开时,会影响前面的变长参数函数 _tprintf(),  
  8. // 导致运行时缓冲区访问违例(Debug 方式产生保护中断),所以不能用前两版带 func(__VA_ARGS__) 的 CALL_TRACE  
  9. #define CALL_TRACE_VOIDPARM(func, ret)  { _tprintf(_T("call: %s\n"), _TSTRINGIZE(func)); ret = func(); }  
  10.   
  11. // 针对返回值、参数均为 void 的函数  
  12. #define CALL_TRACE_VOID_VOIDPARM(func)  { _tprintf(_T("call: %s\n"), _TSTRINGIZE(func)); func(); }  
  13.   
  14. // 用户代码  
  15. // Unicode 方式编译时,输出 call: CreateFileW,并将返回值传给 hFile  
  16. CALL_TRACE_RET(CreateFile, hFile, _T("bbb"), 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);  

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">例子:用 __VA_ARGS__ 格式化 std::string^

  1. // 保证 MAKE_MASK 在所有其它使用 __COUNTER__ 代码之前,这样才能  
  2. // 保证第一次 MAKE_MASK 时,产生 2 << 0  
  3. #define MAKE_MASK0(maskname)    maskname = 1  
  4. #define MAKE_MASK(maskname)     maskname = (2 << __COUNTER__)   // 说明 __COUNTER__ 是支持嵌套展开的  
  5.   
  6. // 用户代码  
  7. enum MyMask  
  8. {  
  9.     MAKE_MASK0(MASK_0), //  2^0:    1  
  10.     MAKE_MASK(MASK_1),  //  2^1:    2 << 0  
  11.     MAKE_MASK(MASK_2),  //  2^2:    2 << 1  
  12.     MAKE_MASK(MASK_3),  //  2^3:    2 << 2  
  13.     MAKE_MASK(MASK_4)   //  2^4:    2 << 3  
  14.     // 最大 MASK = MASK_31  2^31:   2 << 30  
  15. };  

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">例子:用 __FUNCTION__ 打印跟踪函数调用^

  1. // WinBase.h  
  2.   
  3. WINBASEAPI  
  4. __out  
  5. HANDLE  
  6. WINAPI  
  7. CreateFileW(  
  8.     __in     LPCWSTR lpFileName,  
  9.     __in     DWORD dwDesiredAccess,  
  10.     __in     DWORD dwShareMode,  
  11.     __in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,  
  12.     __in     DWORD dwCreationDisposition,  
  13.     __in     DWORD dwFlagsAndAttributes,  
  14.     __in_opt HANDLE hTemplateFile  
  15.     );  

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">Windows API 中的常用宏^

Windows API 包含大量旗标、掩码、状态码、错误码等常量式宏

函数式宏最常用的有:

类型辅助类^
  1. DWORD       MAKEROP4(DWORD fore, DWORD back): used in MaskBlt()  
  2.   
  3. LONG        DIBINDEX(WORD wColorTableIndex)  
  4. COLORREF    PALETTEINDEX(WORD wPaletteIndex)  
  5.   
  6. COLORREF    PALETTERGB(BYTE bRed, BYTE bGreen, BYTE bBlue)  
  7. COLORREF    RGB(BYTE byRed, BYTE byGreen, BYTE byBlue)  
  8.   
  9. BYTE        GetBValue(DWORD rgb)  
  10. BYTE        GetGValue(DWORD rgb)  
  11. BYTE        GetRValue(DWORD rgb)  
  12.   
  13. POINTS      MAKEPOINTS(DWORD dwValue)  

另外,BITMAP_WIDTHBYTES(bits) 不在 Windows API 中,但比较常用于位图:

  1. MAKE_HRESULT(sev, fac, code): 将 severity、facility、code 合并为 HRESULT  
  2. HRESULT_CODE(hr): 取得 HRESULT 的 code 部分  
  3. HRESULT_FACILITY(hr): 取得 HRESULT 的 facility 部分  
  4. HRESULT_SEVERITY(hr): 取得 HRESULT 的 severity 位  
  5.   
  6. HRESULT_FROM_NT(nt_stat): 从 NTSTATUS 变换到 HRESULT  
  7. HRESULT_FROM_WIN32(win_err): 从 Win32 状态码变换到 HRESULT  
  8.   
  9. SUCCEEDED(hr): HRESULT 是否表示成功  
  10. FAILED(hr): HRESULT 是否表示失败  
  11. IS_ERROR(hr): HRESULT 是否表示一个错误  

Win32 状态码没有类似 MAKE_HRESULT 的宏,自定义 Win32 状态码时可以用 mc (Message Compiler) 工具处理 .mc 脚本,自动生成含自定义 Win32 状态码的头文件,同时生成用于 FormatMessage() 的状态码文本描述,参考 MSDN:Message Compiler

也可以自定义用于 Win32 状态码的 MAKE_WINERR():

  1. #define CALLBACK    __stdcall  
  2. #define WINAPI      __stdcall  
  3. #define WINAPIV     __cdecl  
  4. #define APIENTRY    WINAPI  
  5. #define APIPRIVATE  __stdcall  
  6. #define PASCAL      __stdcall  

COM 常用的调用规范辅助宏:

  1. WORD    LANGIDFROMLCID(LCID lcid)  
  2. WORD    MAKELANGID(USHORT primaryLang, USHORT subLang)  
  3. DWORD   MAKELCID(WORD langID, WORD sortID)  
  4. DWORD   MAKESORTLCID(WORD langID, WORD sortID, WORD sortVersion)  
  5. WORD    PRIMARYLANGID(WORD lgid)  
  6. WORD    SORTIDFROMLCID(LCID lcid)  
  7. WORD    SORTVERSIONFROMLCID(LCID lcid)  
  8. WORD    SUBLANGID(WORD lgid)  
资源类^
  1. LPARAM  MAKEIPADDRESS(BYTE b0, BYTE b1, BYTE b2, BYTE b3)  
  2. BYTE    FIRST_IPADDRESS(LPARAM lParam)  
  3. BYTE    SECOND_IPADDRESS(LPARAM lParam)  
  4. BYTE    THIRD_IPADDRESS(LPARAM lParam)  
  5. BYTE    FOURTH_IPADDRESS(LPARAM lParam)  
  6. LPARAM  MAKEIPRANGE(BYTE low, BYTE high)  

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">字符串化操作符 #^

将代码中某个名字转换为字符串字面量,即“加引号”,参考 MSDN: Stringizing Operator

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">用 # 操作构造字符串化宏 STRINGIZE^
  1. // crtdefs.h  
  2. #ifndef _CRT_STRINGIZE  
  3. #define __CRT_STRINGIZE(_Value) #_Value  
  4. #define _CRT_STRINGIZE(_Value) __CRT_STRINGIZE(_Value)  
  5. #endif  
  6.   
  7. #ifndef _CRT_WIDE  
  8. #define __CRT_WIDE(_String) L ## _String  
  9. #define _CRT_WIDE(_String) __CRT_WIDE(_String)  
  10. #endif  
" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">STRINGIZE 的展开规则^

1. 如果 _STRINGIZE() 的参数是宏,那么宏代表的实际值也将被展开,即嵌套展开

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">例子:用 STRINGIZE 查看宏的展开结果^

查看某个宏在当前编译配置 (Debug/Release, ANSI/Unicode) 下,实际表示的东西,如某个 _t 系列函数、Windows API 究竟表示哪个函数,可以利用 _STRINGIZE():

  1. Line: 24  
  2. MAX_PATH: 260  
  3. _DEBUG: 1, _UNICODE: 1  
  4. _tprintf: wprintf  
  5. CreateFile: CreateFileW  

2. 如果 _STRINGIZE() 的参数单纯的变量、函数、类型、const、enum 常量,那么只是将 _STRINGIZE() 括号中的东西加引号而已,如下:

  1. int: int, val: val  
  2. MUSIC_STATE: MUSIC_STATE, ST_STOP: ST_STOP  
  3. ClassTest: ClassTest, obj: obj  
  4. func: func  

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">拼接操作符 ##^

将代码中两个名字拼接到一起,形成一个名字。## 操作“不加引号”,参考 MSDN: Token-Pasting Operator

  1. // tchar.h  
  2. #ifdef _UNICODE  
  3. #define __T(x)      L ## x  
  4. #else  
  5. #define __T(x)      x  
  6.   
  7. #define _T(x)       __T(x)  

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">例子:Windows API 通用句柄类型的定义^

  1. // 音乐播放状态常量  
  2. enum MUSIC_STATE  
  3. {  
  4.     ST_STOP,  
  5.     ST_PLAY,  
  6.     ST_PAUSE,  
  7.     ST_BUTT  
  8. };  
  9.   
  10. // 音乐播放状态结构  
  11. // 里面有一个用于处理特定状态的回调函数 stat_proc  
  12. typedef struct _MusicState  
  13. {  
  14.     MUSIC_STATE     stat;  
  15.     const _TCHAR*   stat_name;  
  16.     int             (*stat_proc)(void*);  
  17. } MusicState;  
  18.   
  19. // 处理特定音乐播放状态的函数  
  20. // 函数名的统一形式 proc_ ## stat,stat 是状态常量的名字  
  21. int proc_ST_STOP(void*);  
  22. int proc_ST_PLAY(void*);  
  23. int proc_ST_PAUSE(void*);  
  24.   
  25. // 初始化音乐播放状态结构  
  26. #define INIT_MUSIC_STATE(stat)  {stat, _TSTRINGIZE(stat), proc_ ## stat}  
  27.   
  28. MusicState g_MusicState[ST_BUTT] =  
  29. {  
  30.     INIT_MUSIC_STATE(ST_STOP),  
  31.     INIT_MUSIC_STATE(ST_PLAY),  
  32.     INIT_MUSIC_STATE(ST_PAUSE)  
  33. };  

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">TCHAR 统一字符类型和处理^

_TCHAR、_T()、_t 系列函数等东西叫做 Generic-Text Mapping,即使用宏进行统一字符类型编写,在不同的字符集编码工程配置 ANSI/UNICODE/MBCS 下替换为不同的实际函数或类型,参考 MSDN:Generic-Text Mappings,Using Generic-Text MappingsUsing TCHAR.H Data Types with _MBCS

工程的字符集配置的宏定义:

ANSI (SBCS, ASCII): _UNICODE 和 _MBCS 均未定义,使用 char 单字节字符集编码
UNICODE: _UNICODE 定义,使用 wchar_t 宽字符集编码,VC 默认 wchar_t 2 字节
MBCS: _MBCS 定义,使用 char 变长字符集编码,一个字符占一个或多个 char

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">_TCHAR, _TEXT()/_T(), _t 系列函数^

根据 _UNICODE、_MBCS 的定义,调用 ANSI/UNICODE/MBCS 不同字符集版本的 CRT 函数,或产生字面量,多在 tchar.h 中声明。_t 字符操作函数参考 MSDN:String Manipulation (CRT)

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">TCHAR, LPTSTR/LPCTSTR, TEXT(), A/W 版本 Windows API^

根据 UNICODE 的定义,调用 ANSI/UNICODE 不同字符集版本的 Windows API,或产生字面量,多在 WinBase.h、Windows.h 中声明

不成文约定:带 _ 前缀的代码,通常对应 CRT,而不带 _ 前缀的东西,通常对应 Windows API。A/W 版本 API 都是接收字符串参数的函数,但并非所有接收字符串的 API 都有 A/W 两个版本,如 GetProcAddress() 只是 A 版本函数,因为 DLL 中的导出符号用 ASCII 英文足够了

宏的缺点和替代方法^

宏是预编译行为,所做的是名字替换,它的缺点和替代方法如下:

宏难于调试^

编译时,宏不会产生用于调试的名字符号。如 #define MAX_PATH 260,在调试时,无法找到其符号名 MAX_PATH,而只是 260 数字

常量式宏可以用 const 和 enum 代替,在调试中可以查看 const、enum 的符号名,并且 const、enum 和宏的运行时开销是相同的(有使用 const、enum 时才会分配内存):

  1. #define SWAP(v1, v2, tmp)   \  
  2.     tmp = v1;               \  
  3.     v1 = v2;                \  
  4.     v2 = tmp;  
  5.   
  6. // 用户代码  
  7. if (condition)  
  8.     SWAP(a, b, t);  // 逻辑问题  
  9.   
  10. if (condition) {  
  11.     SWAP(a, b, t);  // OK  
  12. }  

解决方法:定义宏时用 {} 或 do {} while(0) 包起来,如下:

  1. class TestClass1  
  2. {  
  3. private:  
  4.     int m_Val;  
  5.   
  6. // private 限制对宏 MACRO_DEF_VAL 不起作用  
  7. #define MACRO_DEF_VAL   128  
  8.   
  9. public:  
  10.     static const int CONST_DEF_VAL = 128;  
  11.     enum { ENUM_DEF_VAL = 128 };  
  12. };  
  13.   
  14. class TestClass2  
  15. {  
  16. private:  
  17.     int m_Val;  
  18.   
  19. // 产生 C4005 警告:MACRO_DEF_VAL 被重复定义  
  20. #define MACRO_DEF_VAL   256  
  21.   
  22. public:  
  23.     static const int CONST_DEF_VAL = 256;  
  24.     enum { ENUM_DEF_VAL = 256 };  
  25. };  
  26.   
  27. // 用户代码  
  28.   
  29. // 宏 MACRO_DEF_VAL 是全局的,不能写为 TestClass1::MACRO_DEF_VAL  
  30. _tprintf(_T("TestClass1: %d, %d, %d\n"), MACRO_DEF_VAL, TestClass1::CONST_DEF_VAL, TestClass1::ENUM_DEF_VAL);  
  31. _tprintf(_T("TestClass2: %d, %d, %d\n"), MACRO_DEF_VAL, TestClass2::CONST_DEF_VAL, TestClass2::ENUM_DEF_VAL);  

输出结果:

后面定义的宏 MACRO_DEF_VAL 的值将前面的覆盖了:

  1. #if 0  
  2. XXXXXXXXX  
  3. #endif  
  4.   
  5. #if FALSE  
  6. XXXXXXXXX  
  7. #endif  

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">例子:MFC 中的调试版代码示例^

见上文“MFC 的调试版 new”

AssertValid() 参考 MSDN: MFC ASSERT_VALID and CObject::AssertValid

  1. // DllProj.h  
  2.   
  3. #ifndef _DLLPROJ_H_  
  4. #define _DLLPROJ_H_  
  5.   
  6. #ifdef DLLPROJ_EXPORTS  
  7. #define DLLPROJ_API __declspec(dllexport)  
  8. #else  
  9. #define DLLPROJ_API __declspec(dllimport)  
  10. #endif  
  11.   
  12. #ifdef __cplusplus  
  13. #define EXTERN_C        extern "C"  
  14. #define EXTERN_C_BEGIN  extern "C" {  
  15. #define EXTERN_C_END    }  
  16. #else   // __cplusplus defined  
  17. #define EXTERN_C        extern  
  18. #define EXTERN_C_BEGIN  
  19. #define EXTERN_C_END  
  20. #endif  // __cplusplus NOT defined  
  21.   
  22. // 导出类  
  23. class DLLPROJ_API TestClass  
  24. {  
  25. public:  
  26.     TestClass();  
  27. };  
  28.   
  29. // 导出全局变量,以 C 的链接方式(修饰名、调用约定)  
  30. EXTERN_C DLLPROJ_API int g_TestVal;  
  31.   
  32. // 导出函数  
  33. DLLPROJ_API int TestFunc();  
  34.   
  35. #endif  // _DLLPROJ_H_  

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">例子:用 #undef 解决 wxWidgets 自定义事件链接 BUG^

BUG 参考:wxEvent derived event,Custom Events

BUG 触发条件:以 DLL 方式使用 wxWidgets Windows 版本,即定义了 WXUSINGDLL,使用 DECLARE_EVENT_TYPE() 定义自定事件

BUG 表现:以 __declspec(dllimport) 修饰事件标识,实际上事件标识应该是一个模块内变量,而非导入变量,出现链接问题。MinGW GCC 4 报链接错误,VC 2005 报链接警告:warning C4273: inconsistent dll linkage。BUG 的具体原因请跟踪 wxWidgets 源码 event.h 中的 DECLARE_EVENT_TYPE() 和 dlimpexp.h 中的 WXDLLIMPEXP_CORE 定义

BUG 典型工程:开源下载器 MultiGet svn version 3

BUG 解决方法

方法 1. 不使用旧的 DECLARE_EVENT_TYPE() 而使用 DECLARE_LOCAL_EVENT_TYPE() 定义自定事件
方法 2. 使用 DECLARE_EVENT_TYPE() 前后包含 undefine_WXDLLIMPEXP_CORE.h、redefine_WXDLLIMPEXP_CORE.h 头文件,以便取消和重定义 WXDLLIMPEXP_CORE

方法 2 中的 undefine_WXDLLIMPEXP_CORE.h、redefine_WXDLLIMPEXP_CORE.h 以及使用方法如下:

  1. // redefine_WXDLLIMPEXP_CORE.h  
  2.   
  3. // 不要用 #pragma once 等包含一次技巧  
  4.   
  5. #ifdef REMOVE_WXDLLIMPEXP_CORE  
  6. #   undef WXDLLIMPEXP_CORE  
  7. // 以下块拷贝自 wx-2.8.10 dlimpexp.h,用于恢复 WXDLLIMPEXP_CORE 的原有定义  
  8. // BEGIN  
  9. #   ifdef WXMAKINGDLL_CORE  
  10. #       define WXDLLIMPEXP_CORE WXEXPORT  
  11. #       define WXDLLIMPEXP_DATA_CORE(type) WXEXPORT type  
  12. #   elif defined(WXUSINGDLL)  
  13. #       define WXDLLIMPEXP_CORE WXIMPORT  
  14. #       define WXDLLIMPEXP_DATA_CORE(type) WXIMPORT type  
  15. #   else /* not making nor using DLL */  
  16. #       define WXDLLIMPEXP_CORE  
  17. #       define WXDLLIMPEXP_DATA_CORE(type) type  
  18. #   endif  
  19. // END  
  20. #   undef REMOVE_WXDLLIMPEXP_CORE  
  21. #endif  
  1.   
  2. ///  
  3. /// @file       stdafx.h  
  4. /// @brief      Windows 标准预编译头文件  
  5. ///  
  6. /// 将标准库、运行时库、基本库、Windows API、第三方库的头文件在这里包含,生成  
  7. /// 预编译头文件 MFCBasic.pch  
  8. ///  
  9. /// 如果不修改 stdafx.h,增量编译时便不会重新编译 stdafx.h 中包含的头文件,这样  
  10. /// 加快了编译速度  
  11. ///  
  12. /// @version    <version>  
  13. /// @author     <author>  
  14. /// @date       2011-07  
  15. ///  
  16. /// Copyright (c) 2011, <company>  
  17. /// All rights reserved.  
  18. ///  
  19.   
  20.   
  21. // 典型的“只包含一次”条件编译技巧  
  22. // VC cl 编译器版本 10 以上 (_MSC_VER > 1000) 也可以使用 #pragma once 指令  
  23. #ifndef _STDAFX_H_  
  24. #define _STDAFX_H_  
  25.   
  26. // 排除很少使用的 Windows 头文件  
  27.   
  28. #define WIN32_LEAN_AND_MEAN     // 适用于 Windows API  
  29.   
  30. #ifndef VC_EXTRALEAN  
  31. #define VC_EXTRALEAN            // 适用于 MFC  
  32. #endif  
  33.   
  34. // 指定目标系统和环境 (Windows, IE) 的版本号  
  35.   
  36. #ifndef WINVER  
  37. #define WINVER          0x0501  // 目标系统具有 Windows XP 及以上特性  
  38. #endif  
  39.   
  40. #ifndef _WIN32_WINNT  
  41. #define _WIN32_WINNT    0x0501  // 目标系统具有 Windows XP 及以上特性  
  42. #endif  
  43.   
  44. #ifndef _WIN32_WINDOWS  
  45. #define _WIN32_WINDOWS  0x0410  // 目标系统具有 Windows 98 及以上特性  
  46. #endif  
  47.   
  48. #ifndef _WIN32_IE  
  49. #define _WIN32_IE       0x0600  // 目标系统具有 IE 6.0 及以上特性  
  50. #endif  
  51.   
  52.   
  53. /// Include Header  
  54.   
  55.   
  56. // C 标准库与运行时库 (CRT)  
  57. // BEGIN  
  58. //  
  59. #define _CRT_SECURE_NO_DEPRECATE    // 使用废弃 (deprecated) 的 CRT 函数时,不产生编译警告  
  60. #define _CRT_SECURE_NO_WARNINGS     // 典型的废弃函数有不带缓冲区大小检查的 strcpy()、strcat()、sprintf() 等  
  61.   
  62. #include <stdlib.h>  
  63. #include <tchar.h>  
  64. #include <crtdbg.h>  
  65. #include <string.h>  
  66. //  
  67. // END  
  68.   
  69. // C++ 标准库  
  70. // BEGIN  
  71. //  
  72. #include <exception>  
  73. #include <typeinfo>  
  74. //  
  75. // END  
  76.   
  77. // MFC 库  
  78. // BEGIN  
  79. //  
  80. #ifndef _SECURE_ATL  
  81. #define _SECURE_ATL 1                       // ATL/MFC 的安全设置  
  82. #endif  
  83.   
  84. #define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS  // 使 ATL/MFC 的 CString 具有显式地构造函数 (explicit)  
  85.   
  86. #define _AFX_ALL_WARNINGS                   // 打开 MFC 的所有警告,包括一般可以安全忽略的警告  
  87.   
  88. #include <afxwin.h>     // MFC 核心和标准支持  
  89. #include <afxext.h>     // MFC 扩展支持  
  90.   
  91. #ifndef _AFX_NO_OLE_SUPPORT  
  92. #include <afxdtctl.h>   // MFC 的 IE 4 通用控件支持  
  93. #endif  
  94.   
  95. #ifndef _AFX_NO_AFXCMN_SUPPORT  
  96. #include <afxcmn.h>     // MFC 的 Windows 通用控件支持  
  97. #endif  
  98. //  
  99. // END  
  100.   
  101. // Windows API  
  102. // BEGIN  
  103. //  
  104. // #include <Windows.h>     // 使用 MFC 库时不要包含 Windows.h,MFC 头文件中已包含  
  105. #include <Winsock2.h>  
  106. //  
  107. // END  
  108.   
  109. // Windows 通用控件 ComCtl32.dll 版本 6.0 的内嵌 manifest  
  110. // BEGIN  
  111. //  
  112. #ifdef _UNICODE  
  113. #if defined _M_IX86  
  114. #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")  
  115. #elif defined _M_IA64  
  116. #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"")  
  117. #elif defined _M_X64  
  118. #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"")  
  119. #else  
  120. #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")  
  121. #endif  
  122. #endif  // _UNICODE  
  123. //  
  124. // END  
  125.   
  126. #endif  // _STDAFX_H_  

常用预处理指令^

VC 支持的预处理指令参考 MSDN: Preprocessor Directives

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">#error 产生人工编译错误^

#error 产生 fatal error,编译器输出 #error 后的提示文本。指示该源文件必需使用 C++ 方式编译,如下:

  1. // 实际文件名:test_01.cpp  
  2. #line 1 "test_02.cpp"  
  3.     _tprintf(_T("File: %s, Line: %d\n"), _T(__FILE__), __LINE__);   // 实际第 200 行  

输出:

File: test_02.cpp, Line: 1 
" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif"># 空指令^

没有作用的合法预处理指令行正则表达式:[\t ]*#[\t ]*

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">#pragma 预处理指令^

#pragma 是一组编译器特定的预处理指令,每种编译器的 #pragma 的子指令都有所不同。VC 的 #pragma 指令参考 MSDN: Pragma Directives and the __Pragma Keyword

常用的 #pragma 指令如下:

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">#pragma once 只包含一次头文件^

对头文件只包含一次,如下:

  1. // test.h  
  2. #ifndef _TEST_H_  
  3. #define _TEST_H_  
  4.   
  5. // 头文件中的代码  
  6.   
  7. #endif  // _TEST_H_  

在源文件中多次 #include 包含 test.h 时,不会出现 redefinition 错误

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">#pragma message 编译时输出消息^

#pragma message 在编译过程中,向标准输出或 VC 的 Output 窗口打印指定消息,作用:(1) 告知程序员代码编译和使用的注意事项 (2) 用于查看和诊断实际的编译代码

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">例子:用 #pragma message 和 STRINGIZE 查看宏的展开结果^

例 11 是用 STRINGIZE 在运行时输出宏的展开结果,其实在编译时也可以用 #pragma message 输出,诊断编译的实际代码:

  1. Line: 209  
  2. MAX_PATH: 260  
  3. _DEBUG: 1, _UNICODE: 1  
  4. _tprintf: wprintf  
  5. CreateFile: CreateFileW  
" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">#pragma push_macro/pop_macro 保存和恢复宏定义^

#pragma push_macro/pop_macro 用来解决宏命名冲突问题,如下:

  1. MAX_PATH: 260  
  2. MAX_PATH: 512  
  3. MAX_PATH: 260  
" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">#pragma warning 禁用和启用编译警告^

例子:

  1. // DllProj.h  
  2.   
  3. #ifndef _DLLPROJ_H_  
  4. #define _DLLPROJ_H_  
  5.   
  6. #ifdef DLLPROJ_EXPORTS  
  7. #define DLLPROJ_API __declspec(dllexport)  
  8. #else  
  9. #pragma comment(lib, "DllProj.lib")     // 指示在导入符号时链接 DllProj.lib  
  10. #define DLLPROJ_API __declspec(dllimport)  
  11. #endif  
  12.   
  13. // 省略代码  
  14.   
  15. #endif  // _DLLPROJ_H_  

在使用工程中 #include 该文件,并设置库搜索路径 /LIBPATH,不必指定链接导入库 DllProj.lib

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">#pragma comment(linker) 传递链接选项^

#pragma comment(linker, "link_option")

link_option 只能为以下链接选项:

/DEFAULTLIB
/EXPORT
/INCLUDE
/MANIFESTDEPENDENCY
/MERGE
/SECTION

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">#pragma comment(linker, "/SECTION") 设置区段属性^

设置区段属性的方法有:

(1). 使用模块定义文件 .def 的 SECTIONS 定义,见 MSDN: SECTIONS (C/C++)

(2). 使用 /SECTION 链接选项,见 MSDN: /SECTION (Specify Section Attributes)

(3). 使用 #pragma section 指令创建区段

对于上面的方法 (2),可用 #pragma comment(linker) 指定链接选项

例子:#pragma comment(linker, "/SECTION") 设置可读写、共享区段

  1. #pragma section(".mydata", read, write, shared)     // 在 .obj 中新建可读写、共享区段 .mydata  
  2. // #pragma comment(linker, "/SECTION:.mydata,RWS")  // 作用与上类似:在链接时调整区段属性  
  3. #pragma data_seg(".mydata")                         // 将以下初始化数据放置到 .mydata  
  4.   
  5. // .mydata 区段中的变量定义  
  6.   
  7. #pragma data_seg()                                  // 恢复默认的初始化数据区段 .data  
  8.   
  9. __declspec(allocate(".mydata"))                     // 用  __declspec(allocate) 放置数据到区段  
  10. int g_Var = 0;  

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">#pragma alloc_text 将 C 链接约定的函数放置到区段^

#pragma alloc_text 只能应用于 C 链接约定的函数,即对于 C++ 编译方式,需用 extern "C" 声明函数。所以 #pragma alloc_text 不支持重载函数和类成员函数

#pragma alloc_text 在函数声明与函数定义体之间使用

例子:在可执行、非分页区段中,用 #pragma alloc_text 放置 C 链接约定函数

  1. #pragma section(".mycode", read, execute, nopage)       // 建立可执行、非分页区段  
  2. // #pragma comment(linker, "/SECTION:.mycode,RE!P")     // 作用与上类似:在链接时调整区段属性  
  3.   
  4. #pragma code_seg(".mycode")                             // 将以下函数放到 .mycode 区段中  
  5. void TestFunc_1()  
  6. {  
  7.     // TestFunc_1 函数体  
  8. }  
  9.   
  10. void TestFunc_2()  
  11. {  
  12.     // TestFunc_2 函数体  
  13. }  
  14. #pragma code_seg()                                      // 恢复默认的标准代码区段 .text  

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">#pragma data_seg/bss_seg/const_seg 将数据放置到区段^

数据性质和区段有对应关系,如果放置区段和数据性质冲突,则不会实际放到该区段中:

(1). .data 标准区段,放置初始化非 0 全局数据。用 #pragma data_seg 放置初始化数据,必需显示初始化其中变量(可以初始化为 0),否则不会放入 #pragma data_seg 指定的区段

(2). .bss 标准区段,放置未初始化、默认或显式初始化为 0 的全局数据。注意链接时 .bss 会向 .data 中合并,所以在 .exe/.dll 中看不到 .bss 区段,可查看 .obj 中的 .bss 区段。用 #pragma bss_seg 放置未初始化数据,必需不初始化其中变量(也不能初始化为 0),否则不会放入 #pragma bss_seg 指定的区段

(3). .rdata 标准区段,放置只读的全局常量数据。const 数字类型会编码到代码中(指令立即数),所以不放到 .rdata 中。用 #pragma const_seg 放置只读常量数据

例子:自定义区段和数据性质冲突

以下错误编译器不会报错,但实际没有放置到期望的区段中

  1. // x86 32bit  
  2.   
  3. #pragma pack(4)             // 用一对 #pragma pack(4) | #pragma pack()  
  4. // #pragma pack(push, 4)    // 用一对 #pragma pack(push, 4) | #pragma pack(pop)  
  5. struct TestStruct  
  6. {  
  7.     double  a;              // sizeof(double) = 8  
  8.     int     b;              // sizeof(int) = 4  
  9. };                          // sizeof(TestStruct) = 12  
  10.   
  11. // #pragma pack(4) 会一直作用,直到改变 pack   
  12.   
  13. #pragma pack()              // 恢复编译选项 /Zp 设置的字节对齐  
  14. // #pragma pack(pop)        // 恢复 #pragma pack(push, 4) 之前的字节对齐  
" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">#pragma inline 函数设置^

inline 函数修饰,参考 MSDN: inline, __inline, __forceinline

inline 函数编译优化选项,参考 MSDN: /Ob (Inline Function Expansion)

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">#pragma auto_inline 禁用和启用 auto-inline^

例子:

使用 /O2 编译优化选项,含 /Ob2:启动 auto-inline

  1. #pragma optimize("pt", on)  // 对下面的代码使用 fp:precise, /Ot 优化  
  2.   
  3. // 函数定义  
  4.   
  5. #pragma optimize("", off)   // 关闭上次 #pragma optimize 指定的优化  
  6. #pragma optimize("", on)    // 恢复到编译器 /O 选项指定的优化  

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">#pragma intrinsic 使用 intrinsic 函数^

使用 intrinsic 函数编译选项 /Oi,参考 MSDN: /Oi (Generate Intrinsic Functions)

#pragma intrinsic,参考 MSDN: intrinsic

  1. // 使用 #pragma deprecated  
  2. // BEGIN  
  3. //  
  4. #pragma deprecated(OldClass)  
  5. class OldClass1;  
  6.   
  7. #pragma deprecated(test_func1)  
  8. void old_func1();  
  9. //  
  10. // END  
  11.   
  12. // 使用 __declspec(deprecated)  
  13. // BEGIN  
  14. #define DEPRECATED_WILL_RMOVED  "** will be removed in next version **"  
  15.   
  16. // deprecated() 中的字符串不是必需的,如果有,会在警告时输出  
  17. __declspec(deprecated(DEPRECATED_WILL_RMOVED)) void old_func2();  
  18.   
  19. // 注意 __declspec(deprecated) 修饰 class 时的位置  
  20. class __declspec(deprecated) OldClass2;  
  21. //  
  22. // END  
  23.   
  24. void test()  
  25. {  
  26.     old_func1();    // 产生 C4995 警告  
  27.     OldClass1 obj;  // 产生 C4995 警告  
  28.   
  29.     old_func2();    // 产生 C4996 警告,并输出 "** will be removed in next version **"  
  30.     OldClass2();    // 产生 C4996 警告  
  31. }  
" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">#pragma omp 使用 OpenMP 指令^

指令形式:

#pragma omp omp_directive 

用于多线程、并发编程的 OpenMP 指令,子指令 omp_directive 参考 MSDN: OpenMP Directives

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">#pragma region/endregion 折叠代码块^

标记一整块代码,在 VC 编辑器可折叠成一行 (+) 和展开,见 VC 的 Edit->Outlining 菜单

VC Outlining 常用快捷键:

Ctrl + M, Ctrl + L: 折叠或展开所有的代码块
Ctrl + M, Ctrl + M: 折叠或展开光标所在的代码块

  1. #pragma include_alias(<stdio.h>, <newstdio.h>)  
  2. #pragma include_alias("api.h", "test\api.h")  
  3.   
  4. #include <stdio.h>  
  5. #include "api.h"  

预处理相关编译选项^

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">/D 定义宏^

/D: 定义宏,作用类似 #define,但会去掉选项中的引号
/U: 取消指定的预定义宏,类似 #undef,如 /U _DEBUG
/u: 取消所有的预定义宏。/U 和 /u 都不能取消在源码中用 #define 定义的宏

定义数字^

  • /DTESTMACRO: 等价 #define TESTMACRO 1,整数
  • /DTESTMACRO=1: 同上
  • /DTESTMACRO="1": 同上
  • /DTESTMACRO=3.14: 等价 #define TESTMACRO 3.14,浮点数
  • /DTESTMACRO="3.14": 同上

定义字符串^

  • /DTESTMACRO="abcdef": 等价 #define TESTMACRO abcdef,非字符串字面量(没有引号)
  • /DTESTMACRO=\"abcdef\": 等价 #define TESTMACRO "abcdef",字符串字面量
  • /DTESTMACRO="\"abcdef\"": 同上

空定义^

  • /DTESTMACRO=: 等价 #define TESTMACRO
  • /DTESTMACRO="": 同上
  • /DTESTMACRO=\"\": 等价 #define TESTMACRO "",非空定义,而是空字符串

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">CL 环境变量使用 /D^

SET CL=/DTESTMACRO#1: 用 # 代替 =,等价 /DTESTMACRO=1,即 #define TESTMACRO 1

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">/E, /EP, /P 预处理选项^

/E: 预处理源文件,结果输出到标准输出,去掉注释,在 #inlcude 展开和条件编译周围产生 #line 行号指示
/EP: 和 /E 相似,结果输出到标准输出,但不产生 #line
/P: 和 /E 相似,产生 #line,结果输出到文件 (test.cpp => test.i),相当于 cl /E test.cpp > test.i
/P /EP 联用: 结果输出到文件 test.i,且不产生 #line。/E、/EP、/P 不能和预编译头 PCH 联用
/C: 预处理时保留注释,和 /E、/P、/EP 联用

例子:预处理展开源文件^

源文件 test.cpp:

  1. #line 1 "test.cpp"  
  2. #line 1 "d:\\Visual Studio 8\\VC\\INCLUDE\\stdio.h"  
  3.   
  4. // #line 中 stdio.h 的路径由实际 VC 安装路径而定  
  5. // 这里省略 stdio.h 展开后的大量代码  
  6.   
  7. #line 706 "d:\\Visual Studio 8\\VC\\INCLUDE\\stdio.h"  
  8.   
  9. #line 2 "test.cpp"  
  10.   
  11. int main()  
  12. {  
  13.   
  14.   
  15.   
  16.     printf("Release config\n");  
  17. #line 10 "test.cpp"  
  18.   
  19. // MARK: TESTMACRO value  
  20.     printf("TESTMACRO: %d\n", 1);  
  21.     return 0;  
  22. }  

例子:过滤查看预处理展开结果^

用这种方法可以查看编译过程中,实际的宏展开、预处理结果

以上面的 test.cpp 为例,预处理编译命令和 grep 过滤:

cl /EP /C /DTESTMACRO test.cpp 2>NUL | egrep -A 5 -B 5 "MARK: TESTMACRO" 

2>NUL: 用于屏蔽输出 VC 编译器 banner 和提示、错误信息,用 /nologo 选项也可以
egrep -A 5 -B 5: 表示输出匹配正则表达式前后 5 行

输出结果如下:

  1. test.cpp  
  2. Note: including file: d:\Visual Studio 8\VC\INCLUDE\stdio.h  
  3. Note: including file:  d:\Visual Studio 8\VC\INCLUDE\crtdefs.h  
  4. Note: including file:   d:\Visual Studio 8\VC\INCLUDE\sal.h  
  5. Note: including file:   d:\Visual Studio 8\VC\INCLUDE\vadefs.h  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值