156

如何防止两次包含头文件?问题是我包括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

16 回答 16

257

这个问题是在包含<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>

另请参阅

于 2009-09-03T11:23:11.393 回答
82

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

解决方案:

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

  • WIN32_LEAN_AND_MEAN在之前windows.h或项目范围内定义。但它会排除您可能需要的许多其他东西,您应该自己包含它。

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

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

于 2011-11-28T10:47:14.143 回答
16

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

#include <winsock2.h>
#include <windows.h>
于 2010-07-15T07:24:29.607 回答
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
于 2009-09-03T09:55:13.553 回答
7

我在尝试拉取第三方包时遇到了这个问题,该包显然包含 windows.h 在它混乱的标题中的某个地方。在项目级别进行定义_WINSOCKAPI_比费力地解决问题要容易得多(更不用说更易于维护了)。

于 2009-10-04T19:36:19.837 回答
7

我检查了递归包含,我发现了包含(递归)一些的头文件#include "windows.h"#include "Winsock.h"写了一个#include "Winsock2.h". 在这个文件中,我添加#include "Winsock2.h"为第一个包含。

只是耐心的问题,一个一个看包括并建立这个顺序,先 #include "Winsock2.h"然后#include "windows.h"

于 2014-08-25T17:46:04.853 回答
6

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

#define _WINSOCKAPI_

虽然以下不会:

#define WIN32_LEAN_AND_MEAN
于 2017-05-22T07:21:07.960 回答
5

我发现这个链接windows.h 和 winsock2.h有一个对我来说非常有用的替代方法:

#define _WINSOCKAPI_    // stops windows.h including winsock.h
#include <windows.h>
#include <winsock2.h>

我很难找到问题发生的位置,但是通过添加#define,我能够在没有弄清楚的情况下进行构建。

于 2011-04-01T04:02:20.427 回答
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 上使用 guidgen.exe,在 Linux 上使用 uuidgen -t。

于 2009-09-03T11:45:21.823 回答
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 的模块包含”

仍在尝试在不更改代码的情况下纠正问题。

让我知道这是否有意义。

于 2012-01-09T08:29:09.813 回答
3

#pragma once is based on the full path of the filename. So what you likely have is there are two identical copies of either MyClass.h or Winsock2.h in different directories.

于 2009-09-03T10:37:56.540 回答
2

您应该使用标头保护。

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

#ifndef PATH_FILENAME_H
#define PATH_FILENAME_H

在底部

#endif
于 2009-09-03T09:58:46.337 回答
1

#pragma once即使在 MS 编译器上也是 flakey,并且许多其他编译器不支持。正如许多其他人所提到的,使用包含警卫是要走的路。根本不要使用#pragma once——它会让你的生活更轻松。

于 2009-09-03T10:36:00.773 回答
1

#include 守卫是执行此操作的标准方式。 #pragma once不是,这意味着并非所有编译器都支持它。

于 2009-09-03T10:45:54.040 回答
1

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

头文件:

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

cp类:

//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")
于 2016-10-31T12:04:48.953 回答
0

我实际上遇到了一个问题,我必须将 winsock2.h 定义为第一个包含,它似乎与其他包中的包含有其他问题。希望这对遇到相同问题的人有所帮助,不仅仅是 windows.h,而是所有内容。

于 2018-11-12T19:45:23.707 回答