1.
#运算符.将其后面的宏参数进行字符串化操作(Stringfication),简单说就是在对它所引用的宏变量通过替换后在其左右各加上一个双引号。
#define _STR(s) #s
2.
##运算符用于把参数连接到一起。
预处理程序把出现在##两侧的参数合并成一个符号。
#define NUM(a,b,c) a##b##c
#define STR(a,b,c) a##b##c
3.
#error指令将使编译器显示一条错误信息,然后停止编译。
#line指令可以改变编译器用来指出警告和错误信息的文件号和行号。
#pragma指令没有正式的定义。编译器可以自定义其用途。典型的用法是禁止或允许某些烦人的警告信息。
4.预定义宏
__LINE__ 被编译的文件的行数
__FILE__ 被编译的文件的名字
__DATE__ 编译的日期(格式"Mmm dd yyyy")
__TIME__ 编译的时间(格式"hh:mm:ss")
__STDC__ 如果编译器接受标准C,那么值为1
一C语言的assert #include <crtdefs.h> #undef assert #ifdef NDEBUG #define assert(_Expression) ((void)0) #else #ifdef __cplusplus extern "C" { #endif _CRTIMP void __cdecl _wassert(_In_z_ const wchar_t * _Message, _In_z_ const wchar_t *_File, _In_ unsigned _Line); #ifdef __cplusplus } #endif #define assert(_Expression) (void)( (!!(_Expression)) || (_wassert(_CRT_WIDE(#_Expression), _CRT_WIDE(__FILE__), __LINE__), 0) ) #endif /* NDEBUG */ 1.宏NDEBUG可以重定义,这是良性重定义。 2. #ifndef _CRTIMP #ifdef _DLL #define _CRTIMP __declspec(dllimport) #else /* ndef _DLL */ #define _CRTIMP #endif /* _DLL */ #endif /* _CRTIMP */
动态链接库中定义有两种函数:导出函数(export function)和内部函数(internal function)。
导出函数可以被其它模块调用,内部函数在定义它们的DLL程序内部使用。
用__declspec(dllimport)来导出函数
3.!!(_Expression)) 用!!
让编译器认为_Expression是一个bool值,为true则忽略后面
4._wassert返回void,所以后面加,0
2.MFC的ASSERT,VERIFY,TRACE
TRACE
接收跟printf一样的参数。在debug版的调试状态下出现,在debug窗口中输出信息。在release版本中不计算传入的表达式。
VERIFY
和ASSERT功能类似。所不同的是,在Release版本中,ASSERT不计算输入的表达式的值,而VERIFY计算表达式的值。
//.. \Microsoft Visual Studio 9.0\VC\atlmfc\include\afx.h #ifdef _DEBUG BOOL AFXAPI AfxAssertFailedLine(LPCSTR lpszFileName, int nLine); void AFX_CDECL AfxTrace(LPCTSTR lpszFormat, ...); // Note: file names are still ANSI strings (filenames rarely need UNICODE) void AFXAPI AfxAssertValidObject(const CObject* pOb, LPCSTR lpszFileName, int nLine); void AFXAPI AfxDump(const CObject* pOb); // Dump an object from CodeView #include <atltrace.h> // extern ATL::CTrace TRACE; #define TRACE ATLTRACE #define THIS_FILE __FILE__ #define VERIFY(f) ASSERT(f) //DEBUG下相同 #define DEBUG_ONLY(f) (f) // The following trace macros are provided for backward compatiblity // (they also take a fixed number of parameters which provides // some amount of extra error checking) #define TRACE0(sz) TRACE(_T("%s"), _T(sz)) #define TRACE1(sz, p1) TRACE(_T(sz), p1) #define TRACE2(sz, p1, p2) TRACE(_T(sz), p1, p2) #define TRACE3(sz, p1, p2, p3) TRACE(_T(sz), p1, p2, p3) // These AFX_DUMP macros also provided for backward compatibility #define AFX_DUMP0(dc, sz) dc << _T(sz) #define AFX_DUMP1(dc, sz, p1) dc << _T(sz) << p1 #else // _DEBUG #define VERIFY(f) ((void)(f)) //release下VERIFY仍然计算 #define DEBUG_ONLY(f) ((void)0) #pragma warning(push) #pragma warning(disable : 4793) inline void AFX_CDECL AfxTrace(...) { } #pragma warning(pop) #define TRACE __noop #define TRACE0(sz) #define TRACE1(sz, p1) #define TRACE2(sz, p1, p2) #define TRACE3(sz, p1, p2, p3) #endif // !_DEBUG #define ASSERT(f) DEBUG_ONLY((void) ((f) || !::AfxAssertFailedLine(THIS_FILE, __LINE__) || (AfxDebugBreak(), 0))) /* see ATL headers for commentary on this */ /* We use the name AFXASSUME to avoid name clashes */ #if defined(_PREFAST_) || defined (_DEBUG) #define AFXASSUME(cond) do { bool __afx_condVal=!!(cond); ASSERT(__afx_condVal); __analysis_assume(__afx_condVal); } while(0) #else #define AFXASSUME(cond) ((void)0) #endif #define ASSERT_VALID(pOb) DEBUG_ONLY((::AfxAssertValidObject(pOb, THIS_FILE, __LINE__))) // Debug ASSERTs then throws. Retail throws if condition not met #define ENSURE_THROW(cond, exception) \ do { int __afx_condVal=!!(cond); ASSERT(__afx_condVal); if (!(__afx_condVal)){exception;} } while (false) #define ENSURE(cond) ENSURE_THROW(cond, ::AfxThrowInvalidArgException() ) #define ENSURE_ARG(cond) ENSURE_THROW(cond, ::AfxThrowInvalidArgException() ) // Debug ASSERT_VALIDs then throws. Retail throws if pOb is NULL #define ENSURE_VALID_THROW(pOb, exception) \ do { ASSERT_VALID(pOb); if (!(pOb)){exception;} } while (false) #define ENSURE_VALID(pOb) ENSURE_VALID_THROW(pOb, ::AfxThrowInvalidArgException() ) #define ASSERT_POINTER(p, type) \ ASSERT(((p) != NULL) && AfxIsValidAddress((p), sizeof(type), FALSE)) #define ASSERT_NULL_OR_POINTER(p, type) \ ASSERT(((p) == NULL) || AfxIsValidAddress((p), sizeof(type), FALSE)) //..\Microsoft Visual Studio 9.0\VC\atlmfc\src\mfc\afxasert.cpp #include "stdafx.h" #ifdef _DEBUG // entire file // NOTE: in separate module so it can replaced if needed BOOL AFXAPI AfxAssertFailedLine(LPCSTR lpszFileName, int nLine) { #ifndef _AFX_NO_DEBUG_CRT // we remove WM_QUIT because if it is in the queue then the message box // won't display MSG msg; BOOL bQuit = PeekMessage(&msg, NULL, WM_QUIT, WM_QUIT, PM_REMOVE); BOOL bResult = _CrtDbgReport(_CRT_ASSERT, lpszFileName, nLine, NULL, NULL); if (bQuit) PostQuitMessage((int)msg.wParam); return bResult; #else // Not supported. #error _AFX_NO_DEBUG_CRT is not supported. #endif // _AFX_NO_DEBUG_CRT } #endif // _DEBUG __noop The __noop intrinsic specifies that a function should be ignored and the argument list be parsed but no code be generated for the arguments.
It is intended for use in global debug functions that take a variable number of arguments. 使可变参数的全局debug函数被忽略,参数被解析但不生成代码 #include <stdio.h> #if DEBUG #define PRINT printf_s #else #define PRINT __noop #endif int main() { PRINT("\nhello\n"); }