C ++ Redefinition-Header-Dateien (winsock2.h)

142

Wie verhindere ich, dass Header-Dateien zweimal eingefügt werden? Das Problem ist, ich schließe diein MyClass.h und dann füge ich MyClass.h in viele Dateien ein, so dass es mehrmals enthält und ein Neudefinitionsfehler auftritt. Wie man etwas vorbeugt?

Ich benutze #pragma einmal, anstatt Wachen einzuschließen, und ich denke, das ist in Ordnung.

MyClass.h:

// MyClass.h
#pragma once

#include <winsock2.h>

class MyClass
{

// methods
public:
 MyClass(unsigned short port);
 virtual ~MyClass(void);
};

EDIT: Einige der Fehler, die ich bekomme

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'
akif
quelle
4
Sie verwenden #pragma bereits einmal, daher sollte es nur einmal enthalten sein.
Naveen
1
Ihr Compiler unterstützt Pragma nicht einmal?
Svetlozar Angelov
Ich verwende Visual Studio 2008, warum ist dann <winsock2.h> zweimal enthalten?
Akif
1
Es könnte zweimal aus einigen der enthaltenen Header von MyClass.h
Svetlozar Angelov
5
Winsock2 und Winsock haben gemeinsame Strukturen. Sie müssen nur einen von ihnen
einschließen

Antworten:

233

Dieses Problem wird beim vorherigen <windows.h>Einfügen verursacht <winsock2.h>. Versuchen Sie, Ihre Include-Liste zu ordnen, <windows.h>die nach <winsock2.h>oder _WINSOCKAPI_zuerst definiert wird :

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

Siehe auch dies .

pingw33n
quelle
Ich schließe <windows.h> überhaupt nicht ein, ich weiß, dass <winsock2.h> das für mich tut.
Akif
2
Für mich ist Ihr Code nur <winsock2.h>in MSVC2008 in Ordnung. <windows.h>Durch die Aufnahme werden identische Kompilierungsfehler generiert, die Sie angegeben haben.
Pingw33n
Wird <windows.h> in stdafx.h aufgenommen?
Colin Desmond
1
Diese Lösung hat das Problem für mich in VS 2010 mit SDK 7.1 behoben. Danke pingw33n!
Adamfisk
Ich hatte #include <winsock2.h> #include <ws2tcpip.h> #include <windows.h>in Ordnung und bekam Winsock2, h Datei nicht gefunden. Inbegriffen #define _WINSOCKAPI_ vor allem 3 enthält noch den gleichen Fehler
Ava
75

Wie andere vorgeschlagen haben, liegt das Problem darin, wann windows.hes zuvor enthalten ist WinSock2.h. Weil windows.hbeinhaltet winsock.h. Sie können nicht beide WinSock2.hund verwenden winsock.h.

Lösungen:

  • WinSock2.hVorher einschließen windows.h. Bei vorkompilierten Headern sollten Sie diese dort lösen. Bei einem einfachen Projekt ist es einfach. In großen Projekten (insbesondere beim Schreiben von portablem Code ohne vorkompilierte Header) kann dies jedoch sehr schwierig sein, da der Header mit bereits in einer anderen Header- / Implementierungsdatei WinSock2.henthalten sein windows.hkann, wenn er enthalten ist.

  • WIN32_LEAN_AND_MEANVorher definieren windows.hoder projektweit. Aber es schließt viele andere Dinge aus, die Sie möglicherweise benötigen, und Sie sollten es selbst einschließen.

  • _WINSOCKAPI_Vorher definieren windows.hoder projektweit. Wenn Sie jedoch einschließen, erhalten WinSock2.hSie eine Warnung zur Neudefinition von Makros.

  • Verwenden Sie windows.hanstelle von " WinSock2.hWann" winsock.hfür Ihr Projekt ausreicht (in den meisten Fällen). Dies führt wahrscheinlich zu einer längeren Kompilierungszeit, behebt jedoch alle Fehler / Warnungen.

Pavel Machyniak
quelle
14
WIN32_LEAN_AND_MEANwar die Lösung für mich Panzer viel
Jonatan Cloutier
Informationen zur _WINSOCK_Lösung: Sie sollten keine Warnung zur Neudefinition von Makros erstellen, wenn beide Definitionen identisch sind. Der häufigste Fehler ist, dass Benutzer dem Projekt eine Definition hinzufügen, ohne einen Wert festzulegen, und eine leere Definition erwarten. Wenn Sie jedoch -D_WINSOCK_zur cmd-Zeile hinzufügen , wird diese _WINSOCK_auf 1 gesetzt. Um eine leere Definition zu erstellen, -D_WINSOCK_=muss diese übergeben werden.
Paweł Stankowski
Wenn Sie verwenden #define _WINSOCKAPI_, benötigen Sie möglicherweise auch #define _WINSOCK_DEPRECATED_NO_WARNINGS, abhängig von Ihren Umständen.
Lorien Brune
16

Oh - die Hässlichkeit von Windows ... Die Reihenfolge der Einschlüsse ist hier wichtig. Sie müssen winsock2.h vor windows.h einfügen. Da windows.h wahrscheinlich in Ihrem vorkompilierten Header (stdafx.h) enthalten ist, müssen Sie von dort aus wonock2.h einschließen:

#include <winsock2.h>
#include <windows.h>
Daniel Paull
quelle
14

Mit "Header Guards":

#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
DevSolar
quelle
2
Ich glaube, ich liege falsch (4 Upvotes inzwischen), aber ich denke, die Verwendung von Include-Wachen ist das gleiche wie Pragma, haben Sie beide gesagt?
Svetlozar Angelov
1
Nun, ich habe einmal #pragma, welches afaik die gleichen Header Guards ist
akif
2
@ Angelov: Ja, das sage ich, es sind die gleichen Dinge. Das Problem liegt nicht bei meinen Header-Dateien, aber ich denke, <winsock2.h> selbst hat keine Header-Schutzvorrichtungen oder ist möglicherweise etwas anderes.
akif
1
Per Definition ist #pragma compilerabhängig (nicht standardisiert). Es funktioniert möglicherweise nicht auf allen Compilern. Ich weiß, dass Visual Studio #pargma einmal akzeptiert. Ich bin mir nicht sicher, ob gcc es tut. Ich weiß, dass Wachen IMMER arbeiten. Ich benutze beide #pragma einmal und schließe Schutzvorrichtungen für maximale Schutzfähigkeit ein. Es scheint, dass MSVC die Handhabung von #pragma einmal optimiert hat und gcc die Handhabung von Include-Wachen optimiert hat. Der einzige Unterschied zu meinem Standard-Header besteht darin, dass sich #praga einmal außerhalb der Include-Wachen befindet.
KitsuneYMG
1
Der Befehl '#pragma' ist im ANSI-Standard so festgelegt, dass er einen beliebigen implementierungsdefinierten Effekt hat. Im GNU C-Präprozessor versucht '#pragma' zuerst, das Spiel 'Rogue' auszuführen. Wenn dies fehlschlägt, wird versucht, das Spiel 'hack' auszuführen. Wenn dies fehlschlägt, wird versucht, GNU Emacs mit dem Turm von Hanoi auszuführen. Wenn dies fehlschlägt, wird ein schwerwiegender Fehler gemeldet. In jedem Fall wird die Vorverarbeitung nicht fortgesetzt. - Richard M. Stallman, Der GNU C-Präprozessor, Version
1.34
6

Ich bin auf dieses Problem gestoßen, als ich versucht habe, ein Paket eines Drittanbieters abzurufen, das anscheinend windows.h irgendwo in der Menge der Header enthielt. Das Definieren _WINSOCKAPI_auf Projektebene war viel einfacher (ganz zu schweigen von der Wartbarkeit), als durch die Suppe zu waten und das problematische Include zu beheben.

Yaur
quelle
1
Auf Qt, in der .pro-Datei, sieht es so aus: DEFINES += _WINSOCKAPI_
Phyatt
@phyatt: du solltest das in eine Antwort verwandeln, wenn du es nicht tust, werde ich es tun!
Leif Gruenwoldt
@LeifGruenwoldt los geht's! Froh, dass ich helfen konnte.
Phyatt
6

In VS 2015 funktioniert Folgendes:

#define _WINSOCKAPI_

Während die folgenden nicht:

#define WIN32_LEAN_AND_MEAN
MariuszW
quelle
6

Ich überprüfte die rekursive enthält, habe ich die Header - Dateien entdeckt , die umfassen (rekursiv) einige #include "windows.h"und #include "Winsock.h"und schreiben #include "Winsock2.h". In diesen Dateien habe ich #include "Winsock2.h"als erstes Include hinzugefügt .

Nur eine Frage der Geduld, Blick auf beinhaltet eine nach der anderen und dieser Ordnung zu schaffen, zuerst #include "Winsock2.h"dann#include "windows.h"

kiriloff
quelle
5

Ich habe diesen Link windows.h und winsock2.h gefunden, der eine Alternative hat, die für mich großartig funktioniert hat:

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

Ich hatte Probleme zu finden, wo das Problem aufgetreten ist, aber durch Hinzufügen von #define konnte ich erstellen, ohne es herauszufinden.

Benjamin Herreid
quelle
4

Ich würde aber nicht nur FILENAME_H verwenden

#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

Ich habe immer einen Postfix Guid verwendet. Ich bin vor einigen Jahren auf eine sehr schlechte Codebasis gestoßen, die verschiedene Header-Dateien mit demselben Dateinamen und Guard enthielt. Die fraglichen Dateien hatten eine gleichnamige Klasse definiert. Wenn nur Namespaces verwendet würden. Einige Projekte wurden kompiliert, andere nicht. Die Verwendung eindeutiger Schutzvorrichtungen war ein Teil der Lösung bei der Unterscheidung von Headern und deren Inhalten.

Verwenden Sie unter Windows mit Visual Studio guidgen.exe, unter Linux uuidgen -t.

Sam
quelle
4

Ich bin auf dasselbe Problem gestoßen und habe Folgendes bisher entdeckt:

Aus diesem Ausgabefragment -

c: \ Programme \ Microsoft SDKS \ Windows \ v6.0a \ include \ ws2def.h (91): Warnung C4005: 'AF_IPX': Makro-Neudefinition
c: \ Programme \ Microsoft SDKS \ Windows \ v6.0a \ Include \ Winsock.h (460): Siehe vorherige Definition von 'AF_IPX'.

-Es scheint, dass sowohl ws2def.h als auch winsock.h in Ihrer Lösung enthalten sind.

Wenn Sie sich die Datei ws2def.h ansehen, beginnt sie mit dem folgenden Kommentar:

/*++

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

--*/

Beachten Sie die letzte Zeile - "Diese Datei kann nicht von einem Modul aufgenommen werden, das auch WINSOCK.H enthält."

Ich versuche immer noch, das Problem zu beheben, ohne Änderungen am Code vorzunehmen.

Lassen Sie mich wissen, ob dies sinnvoll ist.

Shailesh Tainwala
quelle
2

Sie sollten Header Guard verwenden.

Setzen Sie diese Zeile oben in die Header-Datei

#ifndef PATH_FILENAME_H
#define PATH_FILENAME_H

und unten

#endif
ntcong
quelle
1
#pragma einmal und Wachen einschließen sind die gleichen Dinge, nicht wahr?
Akif
Sie sind nicht ganz gleich - die Header-Schutzvorrichtungen verhindern die erneute Aufnahme der Datei auf Präprozessorebene, und sie sind offensichtlich ein bisschen portabler als #pragma.
Timo Geusch
1
Ich meinte, sie sind für die gleichen Zwecke gebaut :)
akif
2
#pragma einmal ist nicht Standard, afaik
ntcong
2

#pragma oncebasiert auf dem vollständigen Pfad des Dateinamens. Sie haben also wahrscheinlich zwei identische Kopien von MyClass.h oder Winsock2.h in verschiedenen Verzeichnissen.

soru
quelle
Eine symbolische Verbindung oder eine NTFS-Verbindung führt ebenfalls zum Ausfall des Systems.
Thomi
1

#pragma onceist selbst auf MS-Compilern ein Flakey und wird von vielen anderen Compilern nicht unterstützt. Wie viele andere bereits erwähnt haben, ist die Verwendung von Include-Wachen der richtige Weg. Verwenden Sie es #pragma onceüberhaupt nicht - es wird Ihr Leben viel einfacher machen.

Thomi
quelle
3
Leider habe ich mehr als null verpfuschte Include-Wachen gesehen, entweder wenn ein Tippfehler bedeutet, dass die Wache nicht wirklich funktioniert, oder wenn Dateien mit demselben Namen in verschiedenen Verzeichnissen dasselbe Token verwenden oder wenn das verwendete Token mit einem Doppel beginnt Unterstrich oder Unterstrich dann Großbuchstaben (und ist daher nicht portierbar, genau wie #pragma einmal). Für von Natur aus nicht portierbaren Code, wie alles, was wonSock.h verwendet, war ich von #pragma bis zu dem Punkt, an dem Sie sagten, es sei Flakey, zutiefst unberührt. Wann schlägt es fehl, außer dass es überhaupt nicht unterstützt wird?
Steve Jessop
3
Bei Verwendung verwendet #pragma onceder Compiler den Knotennamen der Header-Datei als eindeutige ID. Dies kann fehlschlagen, wenn Sie symbolische Links oder NTFS-Junctions in Ihrem Quellbaum haben (häufiger als Sie vielleicht denken) oder wenn Sie eine gleichnamige Datei in einem anderen System-Include-Verzeichnis haben (dies ist mir schon einmal passiert, als ich es getan habe Version 1 und Version 2 derselben Bibliothek, die auf zwei verschiedenen Systemen installiert sind, enthalten Pfade. Fazit: Für mich ist es mir lieber, mehr Kontrolle zu haben und mit gelegentlichen Wetware-Fehlern zu leben, als einem Compiler zu vertrauen, der dies für mich erledigt.
Thomi
1

In meinem Projekt (ich verwende VS 2008 SP1) funktioniert nächste Lösung:

Header-Datei:

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

Cpp-Klasse:

//myclass.cpp
#include "Util.h"
#include "winsock2class.h"
#pragma comment(lib, "Ws2_32.lib")

Dabei bedeutet #include "winsock2class.h" die Klasse, die winockock2.h implementiert hat:

//winsock2class.h
#include <winsock2.h>
#include <windows.h>
#pragma comment(lib, "Ws2_32.lib")
Yahor M.
quelle
0

Ich bin tatsächlich auf ein Problem gestoßen, bei dem ich winsock2.h als erstes Include definieren musste. Es scheint, dass es andere Probleme mit Includes aus anderen Paketen gibt. Ich hoffe, dies ist hilfreich für jemanden, der auf dasselbe Problem stößt, nicht nur auf windows.h, sondern auf alles.

Jeff
quelle