C++编程进阶 ANSI C 的宏

代码段1:

//stdafx.h
// stdafx.h : 标准系统包含文件的包含文件,
// 或是经常使用但不常更改的
// 特定于项目的包含文件
//
#pragma once
// 如果必须将位于下面指定平台之前的平台作为目标,请修改下列定义。
// 有关不同平台对应值的最新信息,请参考 MSDN。
#ifndef WINVER     // 允许使用特定于 Windows XP 或更高版本的功能。
#define WINVER 0x0501   // 将此值更改为相应的值,以适用于 Windows 的其他版本。
#endif
#ifndef _WIN32_WINNT   // 允许使用特定于 Windows XP 或更高版本的功能。
#define _WIN32_WINNT 0x0501 // 将此值更改为相应的值,以适用于 Windows 的其他版本。
#endif
#ifndef _WIN32_WINDOWS   // 允许使用特定于 Windows 98 或更高版本的功能。
#define _WIN32_WINDOWS 0x0410 // 将此值更改为适当的值,以指定将 Windows Me 或更高版本作为目标。
#endif
#ifndef _WIN32_IE    // 允许使用特定于 IE 6.0 或更高版本的功能。
#define _WIN32_IE 0x0600 // 将此值更改为相应的值,以适用于 IE 的其他版本。
#endif
#define WIN32_LEAN_AND_MEAN   // 从 Windows 头中排除极少使用的资料
#include <stdio.h>
#include <tchar.h>
#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // 某些 CString 构造函数将是显式的
#ifndef VC_EXTRALEAN
#define VC_EXTRALEAN   // 从 Windows 头中排除极少使用的资料
#endif
#include <afx.h>
#include <afxwin.h>         // MFC 核心组件和标准组件
#include <afxext.h>         // MFC 扩展
#ifndef _AFX_NO_OLE_SUPPORT
#include <afxdtctl.h>   // MFC 对 Internet Explorer 4 公共控件的支持
#endif
#ifndef _AFX_NO_AFXCMN_SUPPORT
#include <afxcmn.h>    // MFC 对 Windows 公共控件的支持
#endif // _AFX_NO_AFXCMN_SUPPORT
#include <iostream>
// TODO: 在此处引用程序需要的其他头文件
//stdafx.cpp
// stdafx.cpp : 只包括标准包含文件的源文件
// LANFILEMAN.pch 将作为预编译头
// stdafx.obj 将包含预编译类型信息
#include "stdafx.h"
// TODO: 在 STDAFX.H 中
// 引用任何所需的附加头文件,而不是在此文件中引用
//Defineh.h
#include <WinSock2.h>
#define SENDFILESIZE (10 * 1024 * 1024)
#define SERVERMODE 1
#define CLIENTMODE 2
#define EXITAPP 2
#define REDO 1
#define MAXCLIENTNUM 10
typedef enum RESULT
{
    FUNCSUCESS,           //函数执行成功
    FUNCFAILD,             //一般的函数执行失败
    WSASTARTUP,
    CREATESOCKET,
    BINDSOCKET,
    LISTEN,
    ACCEPT,
    CREATEFILE,
    READFILE,
    SEND,
    RECV,
    CONNECT,
    WRITEFILE,
    SETENDOFFILE,
    CLOSESOCKET
} Result;
#define WSARETURN(NODE)                          \
 
if(nResult != 0)                             \
{
    \
    cout << "错误码:" << WSAGetLastError() << GetString(NODE);
    \
    return NODE;
    \
}
#define WSACONTINUE(NODE)

代码段2:关于MFC中的#ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]=__FILE__; #endif

情况1:
#ifdef _DEBUG
virtual void AssertValid() const;                 //assert(断言)valid(有效的,正确的)
virtual void Dump(CDumpContext& dc) const;        //存储上下文
#endif

    这两个函数是调试用的,第一个函数检查可用性,即是否有效。第二个函数如果未更改的话,最终调用的是Cwnd::Dump();输出窗口类名,标题名等一系列信息(在输出窗口中)。

#ifdef _DEBUG
#endif
这是条件编译,即如果有#define _DEBUG这两个函数会编译,否则忽略。当你用debug生成时(相对于release)开发环境则自动的加上这个宏定义,这两个函数有效。

情况2:
#ifdef _DEBUG                                   // 判断是否定义_DEBUG
#undef THIS_FILE                                // 取消THIS_FILE的定义
static char THIS_FILE[]=__FILE__;               // 定义THIS_FILE指向文件名
#define new DEBUG_NEW                           // 定义调试new宏,取代new关键字
#endif // 结束

    如果定义了_DEBUG,表示在调试状态下编译,因此相应修改了两个符号的定义。
    THIS_FILE是一个char数组全局变量,字符串值为当前文件的全路径,这样在Debug版本中当程序出错时出错处理代码可用这个变量告诉你是哪个文件中的代码有问题。
    定义 _DEBUG后,由于定义了_DEBUG,编译器确定这是一个调试,编译#ifdef _DEBUG和#endif之间的代码。#undef 表示清除当前定义的宏,使得THIS_FILE无定义。
   __FILE__ 是编译器能识别的事先定义的ANSI C 的6个宏之一。
   DEBUG_NEW定位内存泄露并且跟踪文件名和行号。

情况3:
#ifdef _DEBUG                     //如果是debug状态
#undef THIS_FILE                  //清除THIS_FILE
static char THIS_FILE[]=__FILE__; //定义THIS_FILE为__FILE__(这是当前文件全路径名字)
#define new DEBUG_NEW //定义new为DEBUG_NEW(这个可以检测到内存泄露之类的问题,其实就是可以使用crt开头的那几个调试函数)
#endif

ANSI C 的6个宏:
__FILE__为预编译器常量,返回当前编译的文件名,还有比较常用的几个预编译器常量;
__LINE__编译器正在编译的文件的第几行;
__DATE__返回当前的日期Jul-20-2004;
__TIME__返回当前的时间hh:mm:ss; 
__TIMESTAMP__ 的预定义的编译器宏始终返回时间戳信息。在太平洋标准的时间内无论本地时间和CL.EXE 的运行位置在计算机上的时区。
__STDC__条件编译,意思是:如果定义了标准C或c++,那么编译这句话后面直到#endif以前的源代码。
_STDC__cplusplus这两个都是标准宏,_STDC_表示是是否符合标准C;_cplusplus表示是否是C++。


      曾经一个解释说,多次使用__FILE__宏,虽然得到字符串的内容相同,但是可能地址不同,即同一个字符串常量多次用到时占用不同的地址,这样导致需要的内存增加了。为了检测内在泄露, Debug 版本的 new 附加上了调用 new 的文件名与调用所在的行号信息, 这是通过 __FILE__ 和 __LINE__ 来实现的, 这两个属于预定义的内部宏, 而之所以要用 THIS_FILE 来代替 __FILE__, 是为了减少程序大小: 如果你在一个文件中有 10000 次对 new 的调用, 那么会生成 10000 个当前文件名的常量字符串(第一个都是由 __FILE__ 宏扩展而来的), 最后生成的目标文件会很大, 而用 THIS_FILE 来代替, 当前文件名只有一份, 传递文件名使用 THIS_FILE 指针就可以了。

    __FILE__和__LINE__一样都是编译器定义的宏。当碰到__FILE__时,编译器会把__FILE__替换成一个字符串,这个字符串就是当前在编译的文件的路径名。在DEBUG_NEW的定义中没有直接使用__FILE__,而是用了THIS_FILE,其目的是为了减小目标文件的大小。假设在某个cpp文件中有100处使用了new,如果直接使用__FILE__,那编译器会产生100个常量字符串,这100个字符串都是这个cpp文件的路径名,显然十分冗余。如果使用THIS_FILE,编译器只会产生一个常量字符串,那100处new的调用使用的都是指向常量字符串的指针。
   
    在MFC中,可以使用 DEBUG_NEW 宏代替 new 运算符来帮助定位内存泄漏。在程序的“Debug”版本中,DEBUG_NEW 将为所分配的每个对象跟踪文件名和行号。当编译程序的“Release”版本时,DEBUG_NEW 将解析为不包含文件名和行号信息的简单 new 操作。因此,在程序的“Release”版本中不会造成任何速度损失。  
   
    如果不想重写整个程序来使用 DEBUG_NEW 代替 new,则可以在源文件中定义下面的宏:  
   
    #define  new  DEBUG_NEW  
    当进行对象转储时,用 DEBUG_NEW 分配的每个对象均将显示被分配到的文件和行号,使您可以查明内存泄漏源。  
   
    MFC 框架的“Debug”版本自动使用 DEBUG_NEW,但代码不自动使用它。如果希望利用 DEBUG_NEW 的好处,则必须显式使用 DEBUG_NEW 或 #define new,如上所示。  

    总起来讲,这段代码的作用就是防止内存泄露,减小程序编译开销的。

 

posted @ 2016-04-08 20:32  gukz  阅读(1099)  评论(0编辑  收藏  举报