Файлы заголовков С++ Redefinition (winsock2.h)

Как мне предотвратить включение файлов заголовков в два раза? Проблема в том, что я включаю в 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'

Ответ 1

Эта проблема возникает при включении <windows.h> до <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>

См. также this.

Ответ 2

Как и другие, проблема заключается в том, что windows.h включен до WinSock2.h. Потому что windows.h включает winsock.h. Вы не можете использовать как WinSock2.h, так и winsock.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 достаточно для вашего проекта (в большинстве случаев это). Это, вероятно, приведет к более длительному времени компиляции, но решает любые ошибки/предупреждения.

Ответ 3

О - уродство Windows... Здесь важны порядок включений. Вам нужно включить winsock2.h перед windows.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

Ответ 5

Я столкнулся с этой проблемой, пытаясь вытащить сторонний пакет, который, по-видимому, включал windows.h где-то в нем беспорядок заголовков. Определение _WINSOCKAPI_ на уровне проекта было намного проще (не говоря уже о более ремонтопригодности), чем прохождение через их суп и включение проблемы.

Ответ 6

Я нашел эту ссылку windows.h и winsock2.h, где есть альтернатива, которая отлично мне подходит:

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

У меня были проблемы с поиском, где возникла проблема, но, добавив, что #define я смог собрать, не выяснив это.

Ответ 7

В VS 2015 будет работать следующее:

#define _WINSOCKAPI_

Пока следующее:

#define WIN32_LEAN_AND_MEAN

Ответ 8

Я бы не использовал только 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

Я всегда использовал postfix guid. Несколько лет назад я столкнулся с очень плохой базой кода, которая имела разные заголовочные файлы с тем же именем файла и включала защиту. В рассматриваемых файлах был определен класс с тем же именем. Если использовались только пространства имен. Некоторые проекты, скомпилированные, некоторые не сделали. Использование уникальных охранников было частью решения при разграничении заголовков и их содержимого.

В Windows с Visual Studio используйте guidgen.exe, на Linux uuidgen -t.

Ответ 9

Я проверил рекурсивные включения, я обнаружил заголовочные файлы, которые включают (рекурсивно) некоторые #include "windows.h" и #include "Winsock.h" и записали #include "Winsock2.h". в этих файлах я добавил #include "Winsock2.h" в качестве первого включения.

Просто дело терпения, посмотрите по одному на один и установите этот порядок, сначала #include "Winsock2.h", затем #include "windows.h"

Ответ 10

Я столкнулся с той же проблемой, и вот что я обнаружил до сих пор:

Из этого выходного фрагмента -

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'

-Похоже, что и 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

Вы должны использовать защиту заголовка.

поместите эту строку в верхнюю часть файла заголовка

#ifndef PATH_FILENAME_H
#define PATH_FILENAME_H

и внизу

#endif

Ответ 12

#pragma once основан на полном пути имени файла. Так что вы, вероятно, имеете две идентичные копии MyClass.h или Winsock2.h в разных каталогах.

Ответ 13

#pragma once является ошибочным даже на компиляторах MS и не поддерживается многими другими компиляторами. Как и многие другие люди, использование охранников - это путь. Не используйте #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, но и все включает.