winsock2.h的内容
winsock.h的内容
#ifndef WINSOCKAPI
{
#define WINSOCKAPI
之后全是若_WINSOCKAPI_未被定义,则需要的执行的winsock.h相关定义
}
winsock2.h
再回过头来看winsock2.h,在上述内容之后紧跟着如下宏指令:
/*
Pull in WINDOWS.H if necessary
/
#ifndef _INC_WINDOWS
#include <windows.h>
#endif / _INC_WINDOWS */
其作用是如果用户没有包含windows.h(_INC_WINDOWS在windows.h中定义)就自动包含它,以定义WinSock2.0所需的类型和常量等。
不需要加windows.h 包含好了
windows.h会反向包含winsock2.h或者winsock.h!相互间的包含
其实就是两个头文件前后顺序不同导致的两种情况
第一种
第一种情况则是
#include<winsock2.h>
#include<windows.h>
这种方法是没有问题的,可以被编译 首先,在winsock2.h中 有以下定义winsock2.h 在windows.h之前,这种方法是没有问题的,可以被编译
首先,在winsock2.h中 有以下定义
#ifndef WINSOCK2API
#define WINSOCK2API
#define WINSOCKAPI /* Prevent inclusion of winsock.h in windows.h /
先包含了winsock2.h 就会定义
#define WINSOCK2API
#define WINSOCKAPI
接着 #ifndef _INC_WINDOWS
#include <windows.h>
#endif / _INC_WINDOWS */
需要去加载头文件windows.h 加载过程中因为_WIN32_WINNT >= 0x0400不符合条件,因此会去加载winsock.h. 而winsock.h则是以下定义
#ifndef WINSOCKAPI
{ #define WINSOCKAPI
之后全是若_WINSOCKAPI_未被定义,则需要的执行的winsock.h相关定义 }
因此winsock.h不会被重定义
所以这种加载头文件顺序没有问题
第二种
#include<windows.h>
#include<winsock2.h>
这种顺序自然出现了重定义问题
因为加载windows.h,需要加载winsock.h
因为_WINSOCKAPI_未被宏定义 所以winsock.h顺利被编译,同时_WINSOCKAPI_被宏定义
接着 #include<winsock2.h>
这时候问题来了 因为_WINSOCKAPI_会被重定义!!
因此需要在开头加上#define WIN32_LEAN_AND_MEAN 宏定义
#define WIN32_LEAN_AND_MEAN
#include<windows.h>
#include<winsock2.h>
这样的话 windows.h中则会跳过winsock2.h 或winsock.h的定义 在下方使用不再会出现重定义
#ifndef WINSOCK2API
#define WINSOCK2API
#define WINSOCKAPI
则不会出现_WINSOCKAPI_ 重定义 而winsock2.h中
#ifndef _INC_WINDOWS
#include <windows.h>
#endif /* _INC_WINDOWS */
因为_INC_WINDOWS已经在windows.h中宏定义 因此不会再次加载windows.h造成重定义
宏WIN32_LEAN_AND_MEAN的作用是减小win32头文件尺寸以加快编译速度,一般由AppWizard在stdafx.h中自动定义。_WIN32_WINNT的作用是开启高版本操作系统下的特殊函数,比如要使用可等待定时器(WaitableTimer),就得要求_WIN32_WINNT的值大于或等于0x400。
第二种会因为 define _WIN32_WINNT >= 0x0400而丢失一部分本应包含的头文件 具体原因如下:
WIN32_LEAN_AND_MEAN 是WINDOWS API用于屏蔽一些不常用的API(优化应用程序)才用的。 定义了 WIN32_LEAN_AND_MEAN 就不会使用和链接 SDK 的头文件中相关的
#ifndef WIN32_LEAN_AND_MEAN
#endif //
之间涉及到的API,可以加快链接速度和减小可执行文件体积。
windows.h中的内容
#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
这个宏会屏蔽一些api,那么在使用这个宏的时候,如果又有一些被屏蔽掉api想要使用的话,得加上相应api的宏开关。
补充:
要知道除了VC自带windows库文件外,MS的Platform SDK也含有这些头文件。我们很可能发现在之前能够好好编译的程序在
改变了windows头文件包含路径后又出了问题。原因很简单,Platform SDK中的windows.h与VC自带的文件存在差异,其相同位置的代码如下:
#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>
#include <winsock.h> // 这里直接包含winsock.h
#endif
#ifndef NOCRYPT
#include <wincrypt.h>
#include <winefs.h>
#include <winscard.h>
#endif
#ifndef NOGDI
#ifndef _MAC
#include <winspool.h>
#ifdef INC_OLE1
#include <ole.h>
#else
#include <ole2.h>
#endif /* !INC_OLE1 /
#endif / !MAC /
#include <commdlg.h>
#endif / !NOGDI /
#endif / WIN32_LEAN_AND_MEAN */
/*既然代码不一样,windows.h里却没有任何一个宏定义能够帮助程序辨别当前使用的文件是VC自带的还是PSDK里的。
但我们一般涉及的都是MSDN中windows.h 因此只需宏定义
#define WIN32_LEAN_AND_MEAN就可以
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/hanxiaoyang123/article/details/84001362