windows.h和winsock2.h重定义解决办法

winsock2.h的内容

在文件开头有如下宏定义:
#ifndef WINSOCK2API
#define WINSOCK2API
#define WINSOCKAPI /* Prevent inclusion of winsock.h in windows.h */官方文档也给出警告 在windows.h中防止winsock2.h的加入

winsock.h的内容

#ifndef WINSOCKAPI
{
#define WINSOCKAPI
之后全是若_WINSOCKAPI_未被定义,则需要的执行的winsock.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的内容

<1>#ifndef WIN32_LEAN_AND_MEAN
#include <cderr.h>
#include <dde.h>
#include <ddeml.h>
#include <dlgs.h>
<2>#ifndef _MAC
#include <lzexpand.h>
#include <mmsystem.h>
#include <nb30.h>
#include <rpc.h>
<2>#endif
#include <shellapi.h>
<3>#ifndef _MAC
#include <winperf.h>

<4>#if(_WIN32_WINNT >= 0x0400)
#include <winsock2.h>
#include<mswsock.h>
#else
#include <winsock.h>
<4>#endif /* _WIN32_WINNT= 0x0400 */

<3>#endif // 这里省略掉一部分内容
<1>#endif /* WIN32_LEAN_AND_MEAN */

看到没?windows.h会反向包含winsock2.h或者winsock.h!相互间的包含便是万恶之源!

说来说去 其实就是两个头文件前后顺序不同导致的两种情况

  1. 第一种情况则是
    #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不会被重定义
    所以这种加载头文件顺序没有问题

  2. #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的宏开关。

官方文档:#define WIN32_LEAN_AND_MEAN // make sure all macros are included

意思为确保所有宏都包含在内,这是一个警告作用 提醒你里面有宏定义在内

补充:

没有结束,要知道除了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
就可以

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值