Файлы заголовков С++ 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
вообще - это облегчит вашу жизнь.
Ответ 14
# include guard - это стандартный способ сделать это. # 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, но и все включает.