1 首先明确一个概念 # ifndef
#define
#endif
举例说明
animal.h
#ifndef ANIMAL_H_H //我们一般用#define定义一个宏,是为了在程序中使用,使程
序更加简洁,维护更加方便,然而在此处,我们只是为了判断
#define ANIMAL_H_H ANIMAL_H_H是否定义,以此来避免类重复定义,因此我们没有为
其定义某个具体的值。在选择宏名时,要选用一些不常用的名字,
class animal 因为我们的程序经常会跟别人写的程序集成,如果选用一个很常用
的名字(例如:X),有可能会造成一些不必要的错误
{
public:
animal();
~animal();
void eat();
void sleep();
virtual void breathe();
};
#endif
fish.h
#include "animal.h"
#ifndef FISH_H_H
#define FISH_H_H
class fish:public animal
{
public:
void breathe();
};
#endif
我们再看EX10.cpp的编译过程。当编译器展开animal.h头文件时,条件预处理指令判断ANIMAL_H_H没有定义,于是就定义它,然后继续执行,定义了animal这个类;接着展开fish.h头文件,而在fish.h头文件中也包含了animal.h,再次展开animal.h,这个时候条件预处理指令发现ANIMAL_H_H已经定义,于是跳转到#endif,执行结束。
通过分析,我们发现在这次的编译过程中,animal这个类只定义了一次。
明白了这个概念 在分析。
Windows网络编程至少需要两个头文件:winsock2.h和windows.h
先来分析 winsock.h
#ifndef _WINSOCK2API_
#define _WINSOCK2API_
#define _WINSOCKAPI_ /* Prevent inclusion of winsock.h in windows.h */
_WINSOCK2API_很容易理解,这是最常见的防止头文件重复包含的保护措施。_WINSOCKAPI_的定义则是为了阻止对winsock.h的包含
/*
* Ensure structures are packed consistently.
*/
#include <pshpack4.h>
/*
* Default: include function prototypes, don't include function typedefs.
*/
#ifndef INCL_WINSOCK_API_PROTOTYPES
#define INCL_WINSOCK_API_PROTOTYPES 1
#endif
#ifndef INCL_WINSOCK_API_TYPEDEFS
#define INCL_WINSOCK_API_TYPEDEFS 0
#endif
/*
* Pull in WINDOWS.H if necessary
*/
#ifndef _INC_WINDOWS
#include <windows.h>
#endif /* _INC_WINDOWS */
这里有两个关键点:
(1) 在winsock.h内部当_INC_WINDOWS 没有被定义时 会自动调用windows.h
在这里我们在分析一下 windows.h
1) 在windows.h内部也定义了
_INC_WINDOWS 和winsock2.h
如下:
#ifndef _INC_WINDOWS(基本上在windows.h开始位置)
#define _INC_WINDOWS
。。。。。。(省略)
#ifndef WIN32_LEAN_AND_MEAN
#include <cderr.h>
#include <dde.h>
#include <ddeml.h>
#include <dlgs.h>
#ifndef _MAC
#include <lzexpand.h>
#include <mmsystem.h>
#include <nb30.h>
#include <rpc.h>
#endif
#include <shellapi.h>
#ifndef _MAC
#include <winperf.h>
#if(_WIN32_WINNT >= 0x0400)
#include <winsock2.h>
#include <mswsock.h>
#else
#include <winsock.h>
#endif /* _WIN32_WINNT >= 0x0400 */
#endif
#ifndef NOCRYPT
#include <wincrypt.h>
#endif
#ifndef NOGDI
#include <commdlg.h>
#ifndef _MAC
#include <winspool.h>
#ifdef INC_OLE1
#include <ole.h>
#else
#include <ole2.h>
#endif /* !INC_OLE1 */
#endif /* !MAC */
#endif /* !NOGDI */
#endif /* WIN32_LEAN_AND_MEAN */
#endif /* _INC_WINDOWS */(windows.h倒数第二句)
#endif /* _WINDOWS_ */ (windows.h最后一句)
如果WIN32_LEAN_AND_MEAN没有定义同时WIN32_WINNT >= 0x0400 就会调用
#include <winsock2.h>
#include <mswsock.h>两句
而以‘SOCKET’为例mswsock.h(69) : error C2065: 'SOCKET' : undeclared identifier
原因就在于 :mswsock.h 只是用到了‘SOCKET’而SOCKET是在winsock2.h中被定义的 而且SOCKET的位置在
#ifndef _INC_WINDOWS
#include <windows.h>
#endif /* _INC_WINDOWS */
………………..
typedef u_int SOCKET;
请读者认真看#ifndef _INC_WINDOWS
#include <windows.h>
#endif /* _INC_WINDOWS */
和typedef u_int SOCKET; 在winsock2.h的相对位置SOCKET在#ifndef _INC_WINDOWS
#include <windows.h>
#endif /* _INC_WINDOWS */
其后被定义 所以
在如果先包含winsock2.h再包含windows.h,如果WIN32_LEAN_AND_MEAN未定义且_WIN32_WINNT大于或等于0x400,那么会在winsock2.h—》windows.h----》mswsock.h,此时,mswsock.h里所用的SOCKET类型还尚未定义,因此会出现类型未定义错误.
第二种错误
winsock2.h(99) : error C2011: 'fd_set' : 'struct' type redefinition
错误情形2:
先包含windows.h再包含winsock2.h,如果WIN32_LEAN_AND_MEAN未定义且_WIN32_WINNT未定义或者其版本号小于0x400,那么windows.h会自动导入winsock.h,这样再当winsock2.h被包含时便会引起重定义。
清楚了吧。
再附上一个示例:
#include <windows.h>
#include <winsock2.h>
#pragma comment(lib,"jrtplib.lib")
#pragma comment(lib,"jthread.lib")
#pragma comment(lib,"ws2_32.lib")
#include "header/rtpsession.h"
#include "header/rtppacket.h"
#include "header/rtpudpv4transmitter.h"
#include "header/rtpipv4address.h"
#include "header/rtpsessionparams.h"
#include "header/rtperrors.h"
在程序中 我设计了一个RTP传输类(General Class) 而且在类中没有使用头文件(stdafx.h)
一开始我把
#include <windows.h>
#include <winsock2.h> 放在 #include "header/rtperrors.h" 后面一编译出现了 102 个error(就是上面提到的错误一)
后来我一想很奇怪,没可能性呀。然后我发现了 Jrtplib 的这一堆头文件 我想有一种可能性 就是 在诸如rtpudpv4transmitter.h
中可能也引入了winsock2.h 所以又造成了 错误1 的出现。晚上有时间验证一下。