【问题标题】:C++ Redefinition Header Files (winsock2.h)C++ 重定义头文件 (winsock2.h)
【发布时间】:2010-11-25 05:47:36
【问题描述】:

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

【问题讨论】:

  • 你已经使用过一次#pragma,所以它应该只包含一次。
  • 你的编译器不支持编译指示一次?
  • 我用的是 Visual Studio 2008,那为什么 包含了两次?
  • 它可能会从 MyClass.h 的某些包含的标头中包含两次
  • winsock2 和 winsock 具有共同的结构。您必须只包括其中一个,而不是两者

标签: c++ header redefinition


【解决方案1】:

&lt;winsock2.h&gt; 之前包含&lt;windows.h&gt; 会导致此问题。尝试安排您的包含列表,将 &lt;windows.h&gt; 包含在 &lt;winsock2.h&gt; 之后或首先定义 _WINSOCKAPI_

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

另见this

【讨论】:

  • 我根本不包括 ,我知道 是为我做的。
  • 对我来说,您的代码在 MSVC2008 中仅使用 &lt;winsock2.h&gt; 即可编译。 &lt;windows.h&gt; 包含使其生成与您提供的相同的编译错误。
  • 是否包含在 stdafx.h 中?
  • 这个解决方案在 VS 2010 上使用 SDK 7.1 为我解决了这个问题。谢谢 pingw33n!
  • 我有#include &lt;winsock2.h&gt; #include &lt;ws2tcpip.h&gt; #include &lt;windows.h&gt; 的顺序,并且正在获取winsock2,h 文件未找到。包含#define _WINSOCKAPI_ 以上所有3个仍然包含相同的错误
【解决方案2】:

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

解决方案:

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

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

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

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

【讨论】:

  • WIN32_LEAN_AND_MEAN 是我经常使用坦克的解决方案
  • 关于_WINSOCK_ 解决方案:如果两个定义相同,则不应发出宏重定义警告。常见的错误是人们在没有设置任何值的情况下向项目添加定义并期望空定义。但是,如果在 cmd 行中添加-D_WINSOCK_,它会将_WINSOCK_ 设置为1。要创建空定义,必须传递-D_WINSOCK_=
  • 如果您使用#define _WINSOCKAPI_,您可能还需要#define _WINSOCK_DEPRECATED_NO_WARNINGS,这取决于您的具体情况。
【解决方案3】:

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

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

【讨论】:

    【解决方案4】:

    通过使用“标题保护”:

    #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
    

    【讨论】:

    • 我想我错了(现在有 4 个赞成票),但我认为使用 include 守卫和 pragma 一次是一样的,你把它们都放了吗?
    • 好吧,我有 #pragma once which afaik is the same header guards
    • @Angelov:是的,这就是我所说的它们是相同的东西。问题不在于我的头文件,但我认为 本身没有标头保护,或者可能是其他东西。
    • 根据定义#pragma 依赖于编译器(非标准)。它可能不适用于所有编译器。我知道视觉工作室接受#pargma 一次。我不确定 gcc 是否可以。我知道包括警卫总是有效的。我同时使用 #pragma 一次并包含保护以实现最大的收益。似乎 MSVC 已经优化了一次 #pragma 的处理,而 gcc 已经优化了包含防护的处理。与我的标准标头的唯一区别是 #praga once 在包含保护之外。
    • ANSI 标准中指定的“#pragma”命令具有任意实现定义的效果。在 GNU C 预处理器中,'#pragma' 首先尝试运行游戏'rogue';如果失败,它会尝试运行游戏“hack”;如果失败,它会尝试运行显示河内塔的 GNU Emacs;如果失败,它会报告一个致命错误。在任何情况下,预处理都不会继续。 -- Richard M. Stallman,GNU C 预处理器,1.34 版
    【解决方案5】:

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

    【讨论】:

    • 在 Qt 的 .pro 文件中,它看起来像这样:DEFINES += _WINSOCKAPI_
    • @phyatt:你应该把它变成一个答案,如果你不这样做,我会的!
    • @LeifGruenwoldt 加油!很高兴我能帮上忙。
    【解决方案6】:

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

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

    【讨论】:

    • 在我的情况下,将“windows.h”作为最后一个包含删除了编译器错误。
    【解决方案7】:

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

    #define _WINSOCKAPI_
    

    虽然以下不会:

    #define WIN32_LEAN_AND_MEAN
    

    【讨论】:

      【解决方案8】:

      我找到了这个链接windows.h and winsock2.h,它有一个对我很有效的替代方案:

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

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

      【讨论】:

        【解决方案9】:

        我不会只使用 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。

        【讨论】:

          【解决方案10】:

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

          从此输出片段 -

          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的模块包含”

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

          让我知道这是否有意义。

          【讨论】:

            【解决方案11】:

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

            【讨论】:

            • 符号链接或 NTFS 连接也会导致系统崩溃。
            【解决方案12】:

            你应该使用标题保护。

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

            #ifndef PATH_FILENAME_H
            #define PATH_FILENAME_H
            

            在底部

            #endif
            

            【讨论】:

            • #pragma once 和 include 守卫是一样的东西,不是吗?
            • 它们并不完全相同 - 标头保护将防止在预处理器级别重新包含文件,而且它们显然比 #pragma once 更便携。
            • 我的意思是它们是为相同目的而构建的 :)
            • #pragma once 是非标准的,afaik
            【解决方案13】:

            #pragma once 是不稳定的,即使在 MS 编译器上也是如此,并且许多其他编译器不支持。正如许多其他人所提到的,使用包含警卫是要走的路。完全不要使用#pragma once - 它会让您的生活更轻松。

            【讨论】:

            • 不幸的是,我见过不止零个拙劣的包含守卫,其中拼写错误意味着守卫实际上不起作用,或者不同目录中的同名文件使用相同的标记,或者其中使用的标记以双下划线或下划线开头,然后是大写字母(因此就像#pragma once 一样不可移植)。因此,对于本质上不可移植的代码,就像使用 winsock.h 的任何东西一样,我对#pragma 深感不安,直到你说它是易碎的。除了完全不受支持之外,它什么时候会失败?
            • 使用#pragma once时,编译器将头文件节点名作为唯一Id。如果您的源代码树中有符号链接或 NTFS 结点(比您想象的更常见),或者即使您在另一个系统包含目录中有同名文件(这发生在我之前,当我有安装到两个不同系统包含路径的同一库的版本 1 和版本 2)。底线:对我来说,我更喜欢拥有更多的控制权,并忍受偶尔出现的湿件错误,而不是相信编译器会为我做这件事。
            【解决方案14】:

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

            【讨论】:

              【解决方案15】:

              在我的项目中(我使用 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")
              

              【讨论】:

                【解决方案16】:

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

                【讨论】:

                  猜你喜欢
                  • 2011-08-23
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多