Fichiers d'en-tête de redéfinition C ++ (winsock2.h)

143

Comment éviter d'inclure deux fois les fichiers d'en-tête? Le problème est que j'inclus ledans MyClass.h , puis j'inclus MyClass.h dans de nombreux fichiers, il inclut donc plusieurs fois et une erreur de redéfinition se produit. Comment empêcher?

J'utilise #pragma une fois au lieu d'inclure des gardes, et je suppose que c'est très bien.

MyClass.h:

// MyClass.h
#pragma once

#include <winsock2.h>

class MyClass
{

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

EDIT: peu d'erreurs que je reçois

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
la source
4
Vous utilisez déjà #pragma une fois, il ne devrait donc être inclus qu'une seule fois.
Naveen
1
Votre compilateur ne prend pas en charge pragma une fois?
Svetlozar Angelov
J'utilise Visual Studio 2008, pourquoi est alors <winsock2.h> inclus deux fois?
akif
1
Il peut être inclus deux fois à partir de certains des en-têtes inclus de MyClass.h
Svetlozar Angelov
5
winsock2 et winsock ont ​​des structures communes. Vous devez inclure un seul d'entre eux, pas les deux
Svetlozar Angelov

Réponses:

234

Ce problème est causé lors de l'inclusion <windows.h>avant <winsock2.h>. Essayez d'organiser votre liste d'inclusion qui <windows.h>est incluse après <winsock2.h>ou définissez d' _WINSOCKAPI_abord:

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

Voyez aussi ceci .

pingw33n
la source
Je n'inclus pas du tout <windows.h>, je sais que <winsock2.h> le fait pour moi.
akif le
2
Pour moi, votre code se compile avec seulement <winsock2.h>MSVC2008. <windows.h>l'inclusion le fait générer des erreurs de compilation identiques à celles que vous avez fournies.
pingw33n
<Windows.h> est-il inclus dans stdafx.h?
Colin Desmond
1
Cette solution a résolu le problème pour moi sur VS 2010 avec SDK 7.1. Merci pingw33n!
adamfisk
J'avais #include <winsock2.h> #include <ws2tcpip.h> #include <windows.h>en ordre et obtenais winsock2, fichier h introuvable. Inclus #define _WINSOCKAPI_ au-dessus de tous les 3 comprend toujours la même erreur
Ava
75

Comme d'autres l'ont suggéré, le problème est de savoir quand windows.hest inclus avant WinSock2.h. Parce que windows.hcomprend winsock.h. Vous ne pouvez pas utiliser à la fois WinSock2.het winsock.h.

Solutions:

  • Inclure WinSock2.havant windows.h. Dans le cas des en-têtes précompilés, vous devez le résoudre ici. Dans le cas d'un projet simple, c'est facile. Cependant, dans les grands projets (en particulier lors de l'écriture de code portable, sans en-têtes précompilés), cela peut être très difficile, car lorsque votre en-tête avec WinSock2.hest inclus, windows.hpeut déjà être inclus à partir d'un autre fichier d'en-tête / d'implémentation.

  • Définissez WIN32_LEAN_AND_MEANavant windows.hou à l'échelle du projet. Mais cela exclura de nombreux autres éléments dont vous pourriez avoir besoin et vous devez les inclure vous-même.

  • Définissez _WINSOCKAPI_avant windows.hou à l'échelle du projet. Mais lorsque vous incluez, WinSock2.hvous obtenez un avertissement de redéfinition de macro.

  • Utilisez windows.hplutôt que WinSock2.hquand winsock.hest suffisant pour votre projet (dans la plupart des cas, c'est le cas). Cela entraînera probablement un temps de compilation plus long mais résoudra toutes les erreurs / avertissements.

Pavel Machyniak
la source
14
WIN32_LEAN_AND_MEANétait la solution pour moi beaucoup de chars
Jonatan Cloutier
À propos de la _WINSOCK_solution: vous ne devriez pas grt d'avertissement de redéfinition de macro si les deux définitions sont identiques. Le bogue commun est que les gens ajoutent une définition au projet sans définir de valeur et s'attendent à une définition vide. Cependant, si vous ajoutez -D_WINSOCK_à la ligne cmd, il sera défini _WINSOCK_sur 1. Pour créer une définition vide, -D_WINSOCK_=doit être passé.
Paweł Stankowski
Si vous utilisez #define _WINSOCKAPI_, vous pouvez également avoir besoin #define _WINSOCK_DEPRECATED_NO_WARNINGS, selon votre situation.
Lorien Brune
16

Oh - la laideur de Windows ... L'ordre des inclusions est important ici. Vous devez inclure winsock2.h avant windows.h. Puisque windows.h est probablement inclus à partir de votre en-tête précompilé (stdafx.h), vous devrez inclure winsock2.h à partir de là:

#include <winsock2.h>
#include <windows.h>
Daniel Paull
la source
14

En utilisant des "protections d'en-tête":

#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
la source
2
Je suppose que je me trompe (4 votes positifs maintenant), mais je pense que l'utilisation d'inclure des gardes est la même chose qu'une fois pragma, vous les mettez tous les deux?
Svetlozar Angelov
1
Eh bien, j'ai #pragma une fois qui afaik est les mêmes gardes d'en-tête
akif
2
@Angelov: Oui, c'est ce que je dis, ce sont les mêmes choses. Le problème n'est pas avec mes fichiers d'en-tête, mais je pense que <winsock2.h> lui-même n'a pas de garde d'en-tête ou peut être autre chose.
akif le
1
Par définition, #pragma dépend du compilateur (non standard). Cela peut ne pas fonctionner sur tous les compilateurs. Je sais que le studio visuel accepte une fois #pargma. Je ne sais pas si gcc le fait. Je sais que les gardes travaillent TOUJOURS. J'utilise les deux #pragma une fois et j'inclus des gardes pour une protection maximale. Il semble que MSVC a optimisé la gestion de #pragma une fois et gcc a optimisé la gestion des gardes d'inclusion. La seule différence avec mon en-tête standard est que #praga est une fois en dehors des gardes d'inclusion.
KitsuneYMG
1
La commande '#pragma' est spécifiée dans la norme ANSI pour avoir un effet défini par l'implémentation arbitraire. Dans le préprocesseur GNU C, '#pragma' tente d'abord d'exécuter le jeu 'rogue'; si cela échoue, il essaie de lancer le jeu "hack"; si cela échoue, il essaie d'exécuter GNU Emacs affichant la Tour de Hanoi; si cela échoue, il signale une erreur fatale. Dans tous les cas, le prétraitement ne se poursuit pas. - Richard M. Stallman, Le préprocesseur GNU C, version 1.34
DevSolar
6

J'ai rencontré ce problème en essayant d'extraire un paquet tiers qui incluait apparemment windows.h quelque part dans son désordre d'en-têtes. Définir _WINSOCKAPI_au niveau du projet était beaucoup plus facile (pour ne pas dire plus facile à maintenir) que de patauger dans leur soupe et de résoudre le problème.

Yaur
la source
1
Sur Qt, dans le fichier .pro, cela ressemble à ceci: DEFINES += _WINSOCKAPI_
phyatt
@phyatt: vous devriez en faire une réponse, sinon je le ferai!
Leif Gruenwoldt
@LeifGruenwoldt allez-y! Heureux d'avoir pu aider.
phyatt
6

Dans VS 2015, les éléments suivants fonctionneront:

#define _WINSOCKAPI_

Bien que ce ne soit pas le cas:

#define WIN32_LEAN_AND_MEAN
MariuszW
la source
6

J'ai vérifié les inclusions récursives, j'ai repéré les fichiers d'en-tête qui en incluent (récursivement) certains #include "windows.h"et #include "Winsock.h"et j'écris un fichier #include "Winsock2.h". dans ces fichiers, j'ai ajouté #include "Winsock2.h"comme premier inclure.

Juste une question de patience, regardez les inclus un par un et établissez cet ordre, d'abord #include "Winsock2.h"puis#include "windows.h"

Kiriloff
la source
5

J'ai trouvé ce lien windows.h et winsock2.h qui a une alternative qui a très bien fonctionné pour moi:

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

J'avais du mal à trouver où le problème se produisait, mais en ajoutant cette #define, j'ai pu construire sans le comprendre.

Benjamin Herreid
la source
4

Je n'utiliserais pas uniquement FILENAME_H mais

#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

J'ai toujours utilisé un guid postfix. Je suis tombé sur une base de code très pauvre il y a quelques années qui avait différents fichiers d'en-tête avec le même nom de fichier et include guard. Les fichiers en question avaient défini une classe du même nom. Si seuls les espaces de noms étaient utilisés. Certains projets ont compilé d'autres non. L'utilisation de gardes uniques faisait partie de la solution pour différencier les en-têtes et leur contenu.

Sous Windows avec Visual Studio, utilisez guidgen.exe, sous Linux uuidgen -t.

Sam
la source
4

J'ai rencontré le même problème et voici ce que j'ai découvert jusqu'à présent:

À partir de ce fragment de sortie -

c: \ program files \ microsoft sdks \ windows \ v6.0a \ include \ ws2def.h (91): avertissement C4005: 'AF_IPX': redéfinition de la macro
c: \ program files \ microsoft sdks \ windows \ v6.0a \ include \ winsock.h (460): voir la définition précédente de 'AF_IPX'

-Il semble que ws2def.h et winsock.h ont été inclus dans votre solution.

Si vous regardez le fichier ws2def.h, il commence par le commentaire suivant -

/*++

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

--*/

Faites attention à la dernière ligne - "Ce fichier ne peut pas être inclus par un module qui inclut également WINSOCK.H"

Essayez toujours de résoudre le problème sans apporter de modifications au code.

Faites-moi savoir si cela a du sens.

Shailesh Tainwala
la source
2

Vous devez utiliser la protection d'en-tête.

mettre ces lignes en haut du fichier d'en-tête

#ifndef PATH_FILENAME_H
#define PATH_FILENAME_H

et en bas

#endif
ntcong
la source
1
#pragma une fois et inclure les gardes sont les mêmes choses, n'est-ce pas?
akif le
Ils ne sont pas tout à fait les mêmes - les gardes d'en-tête empêcheront la ré-inclusion du fichier au niveau du préprocesseur, et ils sont évidemment un peu plus portables qu'une fois #pragma.
Timo Geusch
1
Je voulais dire qu'ils sont construits dans le même but :)
akif
2
#pragma once is non-standard, afaik
ntcong
2

#pragma onceest basé sur le chemin complet du nom de fichier. Donc, ce que vous avez probablement, c'est qu'il existe deux copies identiques de MyClass.h ou Winsock2.h dans des répertoires différents.

Soru
la source
un lien symbolique ou une jonction NTFS provoquera également la rupture du système.
Thomi
1

#pragma onceest flakey, même sur les compilateurs MS, et n'est pas pris en charge par de nombreux autres compilateurs. Comme beaucoup d'autres personnes l'ont mentionné, utiliser des gardes d'inclusion est la voie à suivre. Ne l'utilisez pas #pragma oncedu tout - cela vous facilitera la vie.

Thomi
la source
3
Malheureusement, j'ai vu plus de zéro gardes d'inclusion bâclés, soit là où une faute de frappe signifie que le garde ne fonctionne pas réellement, soit où les fichiers du même nom dans différents répertoires utilisent le même jeton, soit où le jeton utilisé commence par un double soulignement ou soulignement puis majuscule (et par conséquent n'est pas portable comme #pragma une fois). Donc, pour le code intrinsèquement non portable, comme tout ce qui utilise winsock.h, je n'ai pas été dérangé par #pragma une fois jusqu'au point où vous avez dit qu'il était floconneux. Quand échoue-t-il, à part de ne pas être pris en charge du tout?
Steve Jessop
3
Lors de l'utilisation #pragma once, le compilateur prend le nom du nœud du fichier d'en-tête comme ID unique. Cela peut échouer si vous avez des liens symboliques ou des jonctions NTFS dans votre arborescence source (plus courant que vous ne le pensez), ou même si vous avez un fichier du même nom dans un autre répertoire d'inclusion système (cela m'est déjà arrivé lorsque j'ai la version 1 et la version 2 de la même bibliothèque installée sur deux systèmes différents incluent des chemins). Conclusion: pour moi, je préfère avoir plus de contrôle et vivre avec des erreurs occasionnelles de wetware, plutôt que de faire confiance à un compilateur pour le faire à ma place.
Thomi
1

#include gardes est la manière standard de faire cela. #pragma ne l'est pas une fois , ce qui signifie que tous les compilateurs ne le supportent pas.

Dima
la source
1

Dans mon projet (j'utilise VS 2008 SP1) fonctionne la solution suivante:

En tête de fichier:

//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")

où #include "winsock2class.h" signifie la classe qui a implémenté winsock2.h:

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

En fait, j'ai rencontré un problème où j'ai dû définir winsock2.h comme premier include, il semble qu'il ait d'autres problèmes avec les inclusions d'autres packages. J'espère que cela sera utile à quelqu'un qui rencontre le même problème, pas seulement windows.h mais tout inclut.

Jeff
la source