C ++重新定义头文件(winsock2.h)


143

如何防止两次包含头文件?问题是我包括MyClass.h中,然后在许多文件中包含MyClass.h,因此它包含多次,并且发生重定义错误。怎么预防?

我使用#pragma一次而不是使用包括卫兵,我想那很好。

MyClass.h:

// MyClass.h
#pragma once

#include <winsock2.h>

class MyClass
{

// methods
public:
 MyClass(unsigned short port);
 virtual ~MyClass(void);
};

编辑:我得到的错误很少

c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(91) : warning C4005: 'AF_IPX' : macro redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(460) : see previous definition of 'AF_IPX'
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(124) : warning C4005: 'AF_MAX' : macro redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(479) : see previous definition of 'AF_MAX'
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(163) : warning C4005: 'SO_DONTLINGER' : macro redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(402) : see previous definition of 'SO_DONTLINGER'
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(206) : error C2011: 'sockaddr' : 'struct' type redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(485) : see declaration of 'sockaddr'
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(384) : error C2143: syntax error : missing '}' before 'constant'
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(384) : error C2143: syntax error : missing ';' before 'constant'
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(384) : error C2059: syntax error : 'constant'
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(437) : error C2143: syntax error : missing ';' before '}'
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(437) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(437) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(518) : warning C4005: 'IN_CLASSA' : macro redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(287) : see previous definition of 'IN_CLASSA'
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(524) : warning C4005: 'IN_CLASSB' : macro redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(293) : see previous definition of 'IN_CLASSB'
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(530) : warning C4005: 'IN_CLASSC' : macro redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(299) : see previous definition of 'IN_CLASSC'
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(541) : warning C4005: 'INADDR_ANY' : macro redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(304) : see previous definition of 'INADDR_ANY'
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(543) : warning C4005: 'INADDR_BROADCAST' : macro redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(306) : see previous definition of 'INADDR_BROADCAST'
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(577) : error C2011: 'sockaddr_in' : 'struct' type redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(312) : see declaration of 'sockaddr_in'
c:\program files\microsoft sdks\windows\v6.0a\include\winsock2.h(132) : error C2011: 'fd_set' : 'struct' type redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(68) : see declaration of 'fd_set'
c:\program files\microsoft sdks\windows\v6.0a\include\winsock2.h(167) : warning C4005: 'FD_SET' : macro redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(102) : see previous definition of 'FD_SET'
c:\program files\microsoft sdks\windows\v6.0a\include\winsock2.h(176) : error C2011: 'timeval' : 'struct' type redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(111) : see declaration of 'timeval'
c:\program files\microsoft sdks\windows\v6.0a\include\winsock2.h(232) : error C2011: 'hostent' : 'struct' type redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(167) : see declaration of 'hostent'
c:\program files\microsoft sdks\windows\v6.0a\include\winsock2.h(245) : error C2011: 'netent' : 'struct' type redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(180) : see declaration of 'netent'
c:\program files\microsoft sdks\windows\v6.0a\include\winsock2.h(252) : error C2011: 'servent' : 'struct' type redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(187) : see declaration of 'servent'
c:\program files\microsoft sdks\windows\v6.0a\include\winsock2.h(264) : error C2011: 'protoent' : 'struct' type redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(199) : see declaration of 'protoent'

4
您已经使用#pragma一次,因此应该只包含一次。
Naveen

1
您的编译器一次不支持编译指示吗?
Svetlozar Angelov

我正在使用Visual Studio 2008,为什么为什么要包含两次<winsock2.h>?
09年

1
MyClass.h
Svetlozar Angelov

5
winsock2和winsock具有相同的结构。您只需要包括其中之一,而不要同时包括两者
Svetlozar Angelov

Answers:


234

包含<windows.h>before 时会导致此问题<winsock2.h>。尝试安排您的包含列表,该列表<windows.h>在其后<winsock2.h>_WINSOCKAPI_首先定义:

#define _WINSOCKAPI_    // stops windows.h including winsock.h
#include <windows.h>
// ...
#include "MyClass.h"    // Which includes <winsock2.h>

另请参见


我根本不包括<windows.h>,我知道<winsock2.h>为我做了。
09年

2
对我来说,您的代码只能<winsock2.h>在MSVC2008中编译。<windows.h>包含使它生成与您提供的相同的编译错误。
pingw33n

<windows.h>是否包含在stdafx.h中?
科林·戴斯蒙德2009年

1
此解决方案为我在带有SDK 7.1的VS 2010上解决了该问题。谢谢pingw33n!
adamfisk

我已#include <winsock2.h> #include <ws2tcpip.h> #include <windows.h>整理好订单,但找不到winsock2,h文件。首先包括的#define _WINSOCKAPI_ 所有3个仍然包含相同的错误
2012年

75

正如其他人所建议的那样,问题在于何时windows.h包括WinSock2.h。因为windows.h包含winsock.h。您不能同时使用WinSock2.hwinsock.h

解决方案:

  • WinSock2.h在之前包括windows.h。如果是预编译头文件,则应在此处解决。在简单项目的情况下,这很容易。但是,在大型项目中(尤其是在编写可移植代码而没有预编译的标头的情况下),这可能会非常困难,因为当WinSock2.h包含标头时,windows.h可以从其他标头/实现文件中包含标头。

  • WIN32_LEAN_AND_MEANwindows.h项目之前或项目范围内进行定义。但是它将排除您可能需要的许多其他内容,因此您应该自己添加。

  • _WINSOCKAPI_windows.h项目之前或项目范围内进行定义。但是当您包含WinSock2.h它时,您会收到宏重新定义警告。

  • 对于您的项目来说,使用windows.h而不是WinSock2.h什么时候winsock.h就足够了(在大多数情况下是)。这可能会导致更长的编译时间,但可以解决所有错误/警告。


14
WIN32_LEAN_AND_MEAN是我坦克的最佳解决方案
Jonatan Cloutier 2012年

关于_WINSOCK_解决方案:如果两个定义相同,则不应该发出宏重新定义警告。常见的错误是人们在不设置任何值的情况下将定义添加到项目中,并且期望空定义。但是,如果添加-D_WINSOCK_到cmd行,它将设置_WINSOCK_为1。要创建空定义,-D_WINSOCK_=必须将其传递。
帕维尔Stankowski

如果您使用#define _WINSOCKAPI_,则#define _WINSOCK_DEPRECATED_NO_WARNINGS根据您的情况,可能还需要。
洛里安·布鲁恩

16

哦-Windows的丑陋...包含顺序在这里很重要。您需要在Windows.h之前包含winsock2.h。由于Windows.h可能包含在预编译的头文件(stdafx.h)中,因此您需要从此处包含winsock2.h:

#include <winsock2.h>
#include <windows.h>

14

通过使用“标题防护”:

#ifndef MYCLASS_H
#define MYCLASS_H

// This is unnecessary, see comments.
//#pragma once

// MyClass.h

#include <winsock2.h>

class MyClass
{

// methods
public:
    MyClass(unsigned short port);
    virtual ~MyClass(void);
};

#endif

2
我猜我错了(到目前为止有4个赞成票),但是我认为使用include防护一次与pragma相同,您将两者都放了吗?
Svetlozar Angelov

1
好吧,我曾经有一次#pragma,其中afaik是相同的头球后卫
akif

2
@Angelov:是的,这就是我说的相同的东西。问题不在于我的头文件,但我认为<winsock2.h>本身没有头保护,或者可能还有其他问题。
09年

1
根据定义,#pragma是编译器相关的(非标准)。它可能不适用于所有编译器。我知道Visual Studio一次接受#pargma。我不确定gcc是否这样做。我知道,包括警卫总是在工作。我同时使用#pragma和包含防护以最大程度地保护它们。似乎MSVC曾经优化了#pragma的处理,而gcc已经优化了include防护的处理。我的标准标头的唯一区别是#praga曾经在include防护之外。
KitsuneYMG

1
在ANSI标准中指定了“ #pragma”命令,以具有任意实现定义的效果。在GNU C预处理器中,“#pragma”首先尝试运行游戏“ rogue”。如果失败,它将尝试运行游戏“ hack”;如果失败,它将尝试运行显示河内塔的GNU Emacs;如果失败,则报告致命错误。在任何情况下,预处理都不会继续。
-Richard

6

我在尝试拉第三方包时遇到了这个问题,该包显然包括windows.h,头文件一团糟。_WINSOCKAPI_在项目级别进行定义要比深入研究并解决有问题的包含项容易得多(更不用说更具可维护性了)。


1
在Qt上的.pro文件中,它看起来像这样: DEFINES += _WINSOCKAPI_
phyatt 2014年

@phyatt:如果不这样做,您应该把它变成答案!
Leif Gruenwoldt

@LeifGruenwoldt去吧!很高兴我能帮助你。
phyatt 2015年

6

在VS 2015中,以下将起作用:

#define _WINSOCKAPI_

虽然以下内容不会:

#define WIN32_LEAN_AND_MEAN

6

我检查递归包括,我看到的头文件,其中包括(递归地)一些#include "windows.h"#include "Winsock.h"和写#include "Winsock2.h"。在此文件中,我添加#include "Winsock2.h"为第一个包含项。

只是出于耐心,先一步一步地建立这个命令, #include "Winsock2.h"然后#include "windows.h"



4

我不会只使用FILENAME_H,而是

#ifndef FILENAME_H_AF06570D_B36E_4B82_8F97_C456AF4A38FD
#define FILENAME_H_AF06570D_B36E_4B82_8F97_C456AF4A38FD

//code stuff
#endif // FILENAME_H_AF06570D_B36E_4B82_8F97_C456AF4A38FD

我一直使用后缀GUID。几年前,我遇到了一个非常糟糕的代码库,该代码库具有具有相同文件名的不同头文件并包含保护。有问题的文件定义了一个具有相同名称的类。如果仅使用名称空间。有些项目没有编译。使用唯一的保护是区分标头及其内容的解决方案的一部分。

在带有Visual Studio的Windows上,在Linux uuidgen -t上使用guidgen.exe。


4

我遇到了同样的问题,这是到目前为止我发现的内容:

从这个输出片段-

c:\ program files \ microsoft sdks \ windows \ v6.0a \ include \ ws2def.h(91):警告C4005:'AF_IPX':宏重新定义
c:\ program files \ microsoft sdks \ windows \ v6.0a \ include \ winsock.h(460):请参阅“ AF_IPX”的先前定义

-您的解决方案中似乎同时包含了ws2def.h和winsock.h。

如果您查看文件ws2def.h,它将以以下注释开头-

/*++

Copyright (c) Microsoft Corporation. All rights reserved.

Module Name:

    ws2def.h

Abstract:

    This file contains the core definitions for the Winsock2
    specification that can be used by both user-mode and 
    kernel mode modules.

    This file is included in WINSOCK2.H. User mode applications
    should include WINSOCK2.H rather than including this file
    directly. This file can not be included by a module that also
    includes WINSOCK.H.

Environment:

    user mode or kernel mode

--*/

请注意最后一行-“此文件也不能包含WINSOCK.H的模块包含”

仍在尝试尝试解决问题而不更改代码。

让我知道这是否有意义。


2

您应该使用标题保护。

将那些行放在头文件的顶部

#ifndef PATH_FILENAME_H
#define PATH_FILENAME_H

在底部

#endif

1
#pragma一次并包含警卫是不是一样?
09年

它们并不完全相同-标头防护会阻止在预处理器级别重新包含文件,此外,它们显然比#pragma更具可移植性。
Timo Geusch

1
我的意思是它们是为相同目的而建造的:)
akif

2
#pragma曾经是非标准的afaik
ntcong

2

#pragma once基于文件名的完整路径。因此,您可能会在不同目录中找到MyClass.h或Winsock2.h的两个相同副本。


符号链接或NTFS结点也会导致系统崩溃。
Thomi

1

#pragma once即使在MS编译器上也是如此,并且许多其他编译器均不支持。正如许多其他人所提到的那样,使用包含防护是必经之路。完全不用使用#pragma once-它会使您的生活更加轻松。


3
不幸的是,我已经看到不止有零个bottomed包含卫队,或者输入错误意味着该卫队实际上不起作用,或者在不同目录中具有相同名称的文件使用了相同的令牌,或者使用的令牌以双精度开头下划线或下划线再大写字母(因此就像#pragma一样不可移植)。因此,对于固有的不可移植的代码(例如使用winsock.h的任何代码),我曾经对#pragma毫无疑虑,直到您说它是flakey为止。除了根本不支持之外,它什么时候会失败?
史蒂夫·杰索普

3
使用时#pragma once,编译器将头文件节点名称作为唯一ID。如果您在源代码树中有符号链接或NTFS结点(比您想象的更常见),或者即使您在另一个系统包含目录中具有相同名称的文件(在我拥有之前,这已经发生在我这里),这可能会失败安装到两个不同系统的同一库的版本1和版本2包含路径)。底线:对我来说,我更愿意拥有更多的控制权,并且偶尔会遇到湿件错误,而不是相信编译器会为我做这件事。
Thomi


1

在我的项目(我使用VS 2008 SP1)中,下一个解决方案是:

头文件:

//myclass.h
#pragma once
#define _WINSOCKAPI_
#include <windows.h>

Cpp类别:

//myclass.cpp
#include "Util.h"
#include "winsock2class.h"
#pragma comment(lib, "Ws2_32.lib")

其中#include“ winsock2class.h”表示实现winsock2.h的类:

//winsock2class.h
#include <winsock2.h>
#include <windows.h>
#pragma comment(lib, "Ws2_32.lib")

0

实际上,我遇到了一个问题,我必须将winsock2.h定义为第一个include,看来其他软件包的include也存在其他问题。希望这对遇到同样问题的人有所帮助,不仅是windows.h,还包括所有问题。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.