File di intestazione di ridefinizione C ++ (winsock2.h)


143

Come posso evitare di includere due volte i file di intestazione? Il problema è che sto includendo ilin MyClass.h e poi includo MyClass.h in molti file, quindi include più volte e si verifica un errore di ridefinizione. Come prevenire?

Sto usando #pragma una volta invece di includere guards, e credo che vada bene.

MyClass.h:

// MyClass.h
#pragma once

#include <winsock2.h>

class MyClass
{

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

EDIT: Pochi degli errori che sto ricevendo

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'

4
Stai già usando #pragma una volta, quindi dovrebbe essere incluso solo una volta.
Naveen,

1
Il tuo compilatore non supporta il pragma una volta?
Svetlozar Angelov,

Sto usando Visual Studio 2008, perché allora <winsock2.h> è incluso due volte?
Akif,

1
Potrebbe essere incluso due volte da alcune delle intestazioni incluse di MyClass.h
Svetlozar Angelov,

5
winsock2 e winsock hanno strutture comuni. Devi includerne solo uno, non entrambi
Svetlozar Angelov,

Risposte:


234

Questo problema si verifica quando si include <windows.h>prima <winsock2.h>. Prova a organizzare l'elenco di inclusione <windows.h>incluso dopo <winsock2.h>o definisci per _WINSOCKAPI_primo:

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

Si veda anche questo .


Non includo affatto <windows.h>, so che <winsock2.h> fa il suo lavoro per me.
Akif,

2
Per me il tuo codice si compila bene solo con <winsock2.h>MSVC2008. <windows.h>l'inclusione fa generare errori di compilazione identici a quelli forniti.
pingw33n,

<Windows.h> è stato incluso in stdafx.h?
Colin Desmond,

1
Questa soluzione ha risolto il problema per me su VS 2010 con SDK 7.1. Grazie pingw33n!
adamfisk,

Avevo #include <winsock2.h> #include <ws2tcpip.h> #include <windows.h>in ordine e stavo ottenendo winsock2, il file h non è stato trovato. Incluso #define _WINSOCKAPI_ soprattutto 3 include ancora lo stesso errore
Ava

75

Come altri hanno suggerito, il problema è quando windows.hè incluso prima WinSock2.h. Perché windows.hinclude winsock.h. Non puoi usare entrambi WinSock2.he winsock.h.

soluzioni:

  • Includi WinSock2.hprima windows.h. Nel caso di intestazioni precompilate, dovresti risolverlo lì. Nel caso di un progetto semplice, è facile. Tuttavia, nei grandi progetti (specialmente quando si scrive codice portatile, senza intestazioni precompilate) può essere molto difficile, perché quando l'intestazione WinSock2.hè inclusa, windows.hpuò già essere inclusa da qualche altro file di intestazione / implementazione.

  • Definire WIN32_LEAN_AND_MEANprima windows.ho a livello di progetto. Ma escluderà molte altre cose di cui potresti aver bisogno e dovresti includerle da solo.

  • Definire _WINSOCKAPI_prima windows.ho a livello di progetto. Ma quando includi WinSock2.hricevi un avviso di ridefinizione delle macro.

  • Usa windows.hinvece di WinSock2.hquando winsock.hè abbastanza per il tuo progetto (nella maggior parte dei casi lo è). Ciò comporterà probabilmente tempi di compilazione più lunghi ma risolverà eventuali errori / avvisi.


14
WIN32_LEAN_AND_MEANè stata la soluzione per me carri armati
Jonatan Cloutier il

Informazioni sulla _WINSOCK_soluzione: non è necessario avvertire di ridefinizione macro se entrambe le definizioni sono identiche. Il bug comune è che le persone aggiungono definizione al progetto senza impostare alcun valore e si aspettano una definizione vuota. Tuttavia, se si aggiunge -D_WINSOCK_alla riga cmd, verrà impostato _WINSOCK_su 1. Per creare una definizione vuota, -D_WINSOCK_=deve essere passato.
Paweł Stankowski il

Se lo usi #define _WINSOCKAPI_, potresti anche aver bisogno #define _WINSOCK_DEPRECATED_NO_WARNINGS, a seconda delle circostanze.
Lorien Brune,

16

Oh, la bruttezza di Windows ... L'ordine delle inclusioni è importante qui. È necessario includere winsock2.h prima di windows.h. Poiché windows.h è probabilmente incluso nell'intestazione precompilata (stdafx.h), dovrai includere winsock2.h da lì:

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

14

Utilizzando "protezioni intestazione":

#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

2
Immagino di sbagliarmi (ormai 4 voti positivi), ma penso che l'uso di include guards sia lo stesso del pragma una volta, li metti entrambi?
Svetlozar Angelov,

1
Bene, una volta ho #pragma, che afaik è lo stesso header guards
akif,

2
@Angelov: Sì, è quello che sto dicendo che sono le stesse cose. Il problema non riguarda i miei file di intestazione, ma penso che <winsock2.h> stesso non abbia protezioni di intestazione o potrebbe essere qualcos'altro.
Akif,

1
Per definizione #pragma dipende dal compilatore (non standard). Potrebbe non funzionare su tutti i compilatori. So che Visual Studio accetta #pargma una volta. Non sono sicuro che gcc lo faccia. So che includere le guardie SEMPRE funziona. Uso entrambi #pragma una volta e includo protezioni per la massima protezione. Sembra che MSVC abbia ottimizzato la gestione di #pragma una volta e gcc abbia ottimizzato la gestione di include guards. L'unica differenza con la mia intestazione standard è che #praga una volta è fuori dalle guardie di inclusione.
KitsuneYMG,

1
Il comando '#pragma' è specificato nello standard ANSI per avere un effetto arbitrario definito dall'implementazione. Nel preprocessore GNU C, "#pragma" tenta innanzitutto di eseguire il gioco "canaglia"; se fallisce, prova a eseguire il gioco "hack"; se fallisce, prova a far funzionare GNU Emacs mostrando la Torre di Hanoi; se fallisce, segnala un errore fatale. In ogni caso, la preelaborazione non continua. - Richard M. Stallman, Il preprocessore GNU C, versione 1.34
DevSolar

6

Ho riscontrato questo problema durante il tentativo di estrarre un pacchetto di terze parti che apparentemente includeva windows.h da qualche parte nel suo casino di intestazioni. Definire _WINSOCKAPI_a livello di progetto è stato molto più facile (per non parlare di più mantenibile) rispetto a guadare attraverso la loro zuppa e risolvere l'inclusione problematica.


1
Su Qt, nel file .pro, è simile al seguente: DEFINES += _WINSOCKAPI_
phyatt

@phyatt: dovresti trasformarlo in una risposta, in caso contrario lo farò!
Leif Gruenwoldt,

@LeifGruenwoldt provaci! Sono contento di poterti aiutare.
Phyatt,

6

In VS 2015 funzioneranno:

#define _WINSOCKAPI_

Mentre quanto segue non lo farà:

#define WIN32_LEAN_AND_MEAN

6

Ho controllato le inclusioni ricorsive, ho individuato i file di intestazione che includono (ricorsivamente) alcuni #include "windows.h"e #include "Winsock.h"e scrivo a #include "Winsock2.h". in questi file, ho aggiunto #include "Winsock2.h"come primo include.

Solo una questione di pazienza, guarda include uno per uno e stabilisci questo ordine, prima #include "Winsock2.h"poi#include "windows.h"


5

Ho trovato questo link windows.h e winsock2.h che ha un'alternativa che ha funzionato benissimo per me:

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

Ho avuto difficoltà a trovare dove si è verificato il problema, ma aggiungendo #define sono stato in grado di costruire senza capirlo.


4

Non userei solo FILENAME_H ma

#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

Ho sempre usato una guida postfix. Alcuni anni fa mi sono imbattuto in una base di codice molto povera che aveva diversi file di intestazione con lo stesso nome di file e include guard. I file in questione avevano definito una classe con lo stesso nome. Se fossero usati solo spazi dei nomi. Alcuni progetti compilati altri no. L'uso di protezioni uniche faceva parte della soluzione nel differenziare le intestazioni e il loro contenuto.

Su Windows con Visual Studio usa guidgen.exe, su Linux uuidgen -t.


4

Ho riscontrato lo stesso problema ed ecco cosa ho scoperto finora:

Da questo frammento di output -

c: \ program files \ microsoft sdks \ windows \ v6.0a \ include \ ws2def.h (91): avviso C4005: 'AF_IPX': ridefinizione macro
c: \ program files \ microsoft sdks \ windows \ v6.0a \ include \ winsock.h (460): vedi la precedente definizione di 'AF_IPX'

-Sembra che sia ws2def.h che winsock.h siano stati inclusi nella soluzione.

Se guardi il file ws2def.h, inizia con il seguente commento:

/*++

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

--*/

Prestare attenzione all'ultima riga: "Questo file non può essere incluso da un modulo che include anche WINSOCK.H"

Sto ancora cercando di correggere il problema senza apportare modifiche al codice.

Fammi sapere se questo ha senso.


2

È necessario utilizzare la protezione dell'intestazione.

mettere quelle righe nella parte superiore del file di intestazione

#ifndef PATH_FILENAME_H
#define PATH_FILENAME_H

e in fondo

#endif

1
#pragma una volta e includi le guardie sono le stesse cose vero?
Akif,

Non sono affatto uguali: le protezioni delle intestazioni impediranno il reinserimento del file a livello di preprocessore, inoltre sono ovviamente un po 'più portabili di #pragma una volta.
Timo Geusch,

1
Volevo dire che sono costruiti per gli stessi scopi :)
akif,

2
#pragma una volta non è standard,
afaik

2

#pragma oncesi basa sul percorso completo del nome file. Quindi quello che probabilmente hai è che ci sono due copie identiche di MyClass.h o Winsock2.h in diverse directory.


un collegamento simbolico o una giunzione NTFS causerà anche la rottura del sistema.
Thomi,

1

#pragma onceè flakey, anche su compilatori MS, e non è supportato da molti altri compilatori. Come molte altre persone hanno già detto, usare include guards è la strada da percorrere. Non usarlo #pragma onceaffatto, ti renderà la vita molto più semplice.


3
Sfortunatamente, ho visto più di zero fallire includere guard, sia dove un errore di battitura significa che la protezione in realtà non funziona, o dove i file con lo stesso nome in directory diverse usano lo stesso token o dove il token utilizzato inizia con un doppio underscore o underscore quindi maiuscola (e quindi non è portatile come una volta #pragma). Quindi per il codice intrinsecamente non portatile, come qualsiasi altra cosa che usi winsock.h, una volta sono stato profondamente senza problemi da #pragma fino al punto in cui hai detto che era flakey. Quando fallisce, oltre a non essere supportato affatto?
Steve Jessop,

3
Durante l'utilizzo #pragma once, il compilatore accetta il nome nodo del file di intestazione come ID univoco. Questo può fallire se hai collegamenti simbolici o giunzioni NTFS nella tua struttura dei sorgenti (più comune di quanto potresti pensare), o anche se hai un file con lo stesso nome in un'altra directory di inclusione del sistema (questo è successo a me prima quando ho la versione 1 e la versione 2 della stessa libreria installata su due sistemi diversi includono percorsi). In conclusione: per me, preferisco avere più controllo e vivere con l'errore occasionale di wetware, piuttosto che fidarmi di un compilatore per farlo per me.
Thomi,


1

Nel mio progetto (utilizzo VS 2008 SP1) funziona la prossima soluzione:

File di intestazione:

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

Classe Cpp:

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

dove #include "winsock2class.h" indica la classe che ha implementato winsock2.h:

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

0

In realtà ho riscontrato un problema in cui dovevo definire winsock2.h come primo include, sembra che abbia altri problemi con include da altri pacchetti. Spero che questo sia utile a qualcuno che ha lo stesso problema, non solo windows.h ma tutto include.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.