Jak zapobiec dwukrotnemu dołączaniu plików nagłówkowych? Problem w tym, że dołączam plikw MyClass.h, a następnie włączam MyClass.h do wielu plików, więc zawiera wiele razy i występuje błąd redefinicji. Jak zapobiegać?
Używam raz #pragma zamiast włączać strażników i myślę, że to w porządku.
MyClass.h:
// MyClass.h
#pragma once
#include <winsock2.h>
class MyClass
{
// methods
public:
MyClass(unsigned short port);
virtual ~MyClass(void);
};
EDYCJA: Kilka błędów, które otrzymuję
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'
c++
header
redefinition
akif
źródło
źródło
Odpowiedzi:
Ten problem występuje w przypadku dołączania
<windows.h>
wcześniej<winsock2.h>
. Spróbuj ułożyć listę włączeń, która<windows.h>
jest dołączona po<winsock2.h>
lub zdefiniowana jako_WINSOCKAPI_
pierwsza:Zobacz także to .
źródło
<winsock2.h>
w MSVC2008.<windows.h>
Włączenie powoduje, że generuje identyczne błędy kompilacji, jak podałeś.#include <winsock2.h> #include <ws2tcpip.h> #include <windows.h>
w porządku i otrzymywałem winsock2, plik h nie został znaleziony. Zawarte#define _WINSOCKAPI_
przede wszystkim 3 zawiera wciąż ten sam błądJak sugerowali inni, problem polega na tym, kiedy
windows.h
zostało uwzględnione wcześniejWinSock2.h
. Ponieważwindows.h
obejmujewinsock.h
. Nie możesz używać obuWinSock2.h
iwinsock.h
.Rozwiązania:
Uwzględnij
WinSock2.h
przedwindows.h
. W przypadku prekompilowanych nagłówków należy to tam rozwiązać. W przypadku prostego projektu jest to łatwe. Jednak w dużych projektach (szczególnie przy pisaniu kodu przenośnego, bez prekompilowanych nagłówków) może to być bardzo trudne, ponieważ gdy twój nagłówekWinSock2.h
jest dołączony,windows.h
może być już dołączony z innego pliku nagłówka / implementacji.Zdefiniuj
WIN32_LEAN_AND_MEAN
przedwindows.h
lub w całym projekcie. Ale wykluczy wiele innych rzeczy, których możesz potrzebować i powinieneś dołączyć je samodzielnie.Zdefiniuj
_WINSOCKAPI_
przedwindows.h
lub w całym projekcie. Ale po uwzględnieniuWinSock2.h
otrzymasz ostrzeżenie o przedefiniowaniu makra.Użyj
windows.h
zamiastWinSock2.h
kiedywinsock.h
jest wystarczające dla twojego projektu (w większości przypadków jest). Prawdopodobnie spowoduje to wydłużenie czasu kompilacji, ale rozwiązuje wszelkie błędy / ostrzeżenia.źródło
WIN32_LEAN_AND_MEAN
było dla mnie rozwiązaniem często_WINSOCK_
rozwiązaniu: Nie powinieneś grtować ostrzeżenia przed redefinicją makr, jeśli obie definicje są identyczne. Częstym błędem jest to, że ludzie dodają definicję do projektu bez ustawiania żadnej wartości i oczekują pustej definicji. Jednakże, jeśli dodasz-D_WINSOCK_
do linii cmd, ustawi się ona_WINSOCK_
na 1. Aby utworzyć pustą definicję,-D_WINSOCK_=
należy ją przekazać.#define _WINSOCKAPI_
, możesz również potrzebować#define _WINSOCK_DEPRECATED_NO_WARNINGS
, w zależności od okoliczności.Aha - brzydota Windowsa ... Kolejność włączeń jest tutaj ważna. Musisz dołączyć winsock2.h przed windows.h. Ponieważ windows.h jest prawdopodobnie zawarty w twoim prekompilowanym nagłówku (stdafx.h), będziesz musiał dołączyć winsock2.h stamtąd:
źródło
Używając „osłon nagłówka”:
źródło
Napotkałem ten problem, próbując wyciągnąć pakiet innej firmy, który najwyraźniej zawierał windows.h gdzieś w bałaganie nagłówków. Definiowanie
_WINSOCKAPI_
na poziomie projektu było znacznie łatwiejsze (nie wspominając o łatwiejszym w utrzymaniu) niż brodzenie przez zupę i naprawianie problematycznego dołączenia.źródło
DEFINES += _WINSOCKAPI_
W VS 2015 będą działać:
Podczas gdy następujące nie będą:
źródło
Sprawdziłem rekurencyjne obejmuje dostrzegłem pliki nagłówkowe, które obejmują (rekurencyjnie) niektóre
#include "windows.h"
a#include "Winsock.h"
i napisać#include "Winsock2.h"
. w tych plikach dodałem#include "Winsock2.h"
jako pierwsze dołączenie.Tylko kwestia cierpliwości, spojrzenie obejmuje jeden po drugim oraz stworzenie takiej kolejności, najpierw
#include "Winsock2.h"
następnie#include "windows.h"
źródło
Znalazłem ten link windows.h i winsock2.h, który ma alternatywę, która działała świetnie:
Miałem problem ze znalezieniem miejsca, w którym wystąpił problem, ale po dodaniu tego #define udało mi się zbudować bez rozwiązania problemu.
źródło
Nie użyłbym tylko FILENAME_H, ale
Zawsze używałem guidu Postfix. Kilka lat temu natknąłem się na bardzo słabą bazę kodu, która miała różne pliki nagłówkowe o tej samej nazwie i zawierała ochronę. Wspomniane pliki zdefiniowały klasę o tej samej nazwie. Gdyby użyto tylko przestrzeni nazw. Niektóre projekty zostały skompilowane, inne nie. Użycie unikalnych osłon było częścią rozwiązania polegającego na rozróżnieniu nagłówków i ich zawartości.
W systemie Windows z programem Visual Studio użyj guidgen.exe, w systemie Linux uuidgen -t.
źródło
Napotkałem ten sam problem i oto, co odkryłem do tej pory:
Z tego fragmentu wyjściowego -
-Wydaje się, że zarówno ws2def.h, jak i winsock.h zostały uwzględnione w Twoim rozwiązaniu.
Jeśli spojrzysz na plik ws2def.h, zaczyna się on od następującego komentarza -
Zwróć uwagę na ostatnią linię - „Ten plik nie może być dołączony przez moduł, który zawiera również WINSOCK.H”
Nadal próbuję rozwiązać problem bez wprowadzania zmian w kodzie.
Daj mi znać, jeśli to ma sens.
źródło
Powinieneś użyć ochrony nagłówka.
umieść te linie na górze pliku nagłówkowego
i na dole
źródło
#pragma once
opiera się na pełnej ścieżce nazwy pliku. Więc prawdopodobnie masz dwie identyczne kopie MyClass.h lub Winsock2.h w różnych katalogach.źródło
#pragma once
jest niestabilny, nawet na kompilatorach MS i nie jest obsługiwany przez wiele innych kompilatorów. Jak wiele innych osób wspomniało, najlepszym rozwiązaniem jest użycie osłon włączających. W ogóle nie używaj#pragma once
- znacznie ułatwi ci to życie.źródło
#pragma once
kompilator przyjmuje nazwę węzła pliku nagłówka jako unikalny identyfikator. Może się to nie powieść, jeśli masz dowiązania symboliczne lub połączenia NTFS w drzewie źródłowym (częściej niż myślisz), lub nawet jeśli masz plik o tej samej nazwie w innym katalogu systemowym (zdarzyło mi się to wcześniej, gdy wersja 1 i wersja 2 tej samej biblioteki zainstalowanej w dwóch różnych systemach zawierają ścieżki). Podsumowując: wolę mieć większą kontrolę i żyć z okazjonalnym błędem oprogramowania wetware, niż ufać kompilatorowi, że zrobi to za mnie.# Uwzględnij strażników to standardowy sposób na to. #pragma raz nie jest, co oznacza, że nie wszystkie kompilatory ją obsługują.
źródło
W moim projekcie (używam VS 2008 SP1) działa następne rozwiązanie:
Plik nagłówkowy:
Klasa CPP:
gdzie #include „winsock2class.h” oznacza klasę, która zaimplementowała winsock2.h:
źródło
Właściwie natknąłem się na problem, w którym musiałem zdefiniować winsock2.h jako pierwsze dołączenie, wydaje się, że ma inne problemy z dołączeniami z innych pakietów. Mam nadzieję, że jest to pomocne dla kogoś, kto napotka ten sam problem, nie tylko windows.h, ale wszystkie zawiera.
źródło