Comment puis-je empêcher 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, de sorte qu'il inclut plusieurs fois et qu'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 ça va.
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'
Ce problème est dû à l'inclusion de <windows.h>
avant <winsock2.h>
. Essayez d'organiser votre liste d'inclusion de sorte que <windows.h>
soit inclus après <winsock2.h>
ou définissez d'abord _WINSOCKAPI_
:
#define _WINSOCKAPI_ // stops windows.h including winsock.h
#include <windows.h>
// ...
#include "MyClass.h" // Which includes <winsock2.h>
Voir aussi this .
Comme d'autres l'ont suggéré, le problème est que windows.h
est inclus avant WinSock2.h
. Parce que windows.h
inclut winsock.h
. Vous ne pouvez pas utiliser à la fois WinSock2.h
et winsock.h
.
Solutions:
Inclure WinSock2.h
avant windows.h
. Dans le cas des en-têtes précompilés, vous devriez le résoudre ici. Dans le cas d'un projet simple, c'est facile. Toutefois, dans les grands projets (en particulier lors de l'écriture de code portable, sans en-têtes précompilés), cela peut s'avérer très difficile, car lorsque votre en-tête avec WinSock2.h
est inclus, windows.h
peut déjà être inclus à partir d'un autre fichier d'en-tête/implémentation.
Définissez WIN32_LEAN_AND_MEAN
avant windows.h
ou à l’échelle du projet. Mais cela exclura beaucoup d'autres choses dont vous pourriez avoir besoin et vous devriez les inclure par vous-même.
Définissez _WINSOCKAPI_
avant windows.h
ou à l’échelle du projet. Mais lorsque vous incluez WinSock2.h
, vous obtenez un avertissement concernant la redéfinition des macros.
Utilisez windows.h
au lieu de WinSock2.h
lorsque winsock.h
est 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 les erreurs/avertissements.
En utilisant "gardes 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
Oh, la laideur de Windows ... L'ordre des inclusions est important ici. Vous devez inclure winsock2.h avant windows.h. Comme windows.h est probablement inclus dans votre en-tête précompilé (stdafx.h), vous devrez inclure winsock2.h à partir de cet emplacement:
#include <winsock2.h>
#include <windows.h>
J'ai rencontré ce problème en essayant d'extraire un package tiers qui, apparemment, incluait windows.h quelque part dans son fouillis d'en-têtes. Définir _WINSOCKAPI_
au niveau du projet était beaucoup plus facile (pour ne pas dire plus facile à gérer) que de patauger dans leur soupe et de corriger l'inclinaison problématique.
Je n'utiliserais pas seulement 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 contenait différents fichiers d'en-tête portant le même nom de fichier et incluant guard. Les fichiers en question avaient défini une classe du même nom. Si seuls les espaces de noms ont été utilisés. Certains projets compilés, 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.
J'ai trouvé ce lien windows.h et winsock2.h qui propose 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 la cause du problème, mais en ajoutant cette définition, je pouvais construire sans le comprendre.
J'ai vérifié les inclusions récursives, j'ai repéré les fichiers d'en-tête qui incluent (récursivement) certains #include "windows.h"
et "#include" Winsock.h "and write a
# include" Winsock2.h ". in this files, i added
# include" Winsock2.h "` comme premier include.
Juste une question de patience, regardez inclut un par un et établissez cet ordre, d'abord #include "Winsock2.h"
puis #include "windows.h"
Dans VS 2015, ce qui suit fonctionnera:
#define _WINSOCKAPI_
Alors que ce qui suit ne va pas:
#define WIN32_LEAN_AND_MEAN
J'ai rencontré le même problème et voici ce que j'ai découvert jusqu'à présent:
De ce fragment de sortie -
c:\programmes\Microsoft sdks\windows\v6.0a\include\ws2def.h (91): avertissement C4005: 'AF_IPX': redéfinition des macros. 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"
J'essaie toujours de rectifier le problème sans apporter de modifications au code.
Faites-moi savoir si cela a du sens.
#pragma once
est basé sur le chemin complet du nom du fichier. Vous avez donc probablement deux copies identiques de MyClass.h ou de Winsock2.h dans des répertoires différents.
Vous devriez utiliser l'en-tête de garde.
mettre ces lignes en haut du fichier d'en-tête
#ifndef PATH_FILENAME_H
#define PATH_FILENAME_H
et en bas
#endif
#include gardes sont le moyen standard de le faire. #pragma once n'est pas, ce qui signifie que tous les compilateurs ne le supportent pas.
Dans mon projet (j'utilise VS 2008 SP1), la solution suivante fonctionne:
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")
#pragma once
est floconneux, même sur les compilateurs MS, et n'est pas pris en charge par beaucoup d'autres compilateurs. Comme beaucoup de personnes l'ont mentionné, le recours à des gardes est la voie à suivre. N'utilisez pas du tout #pragma once
- cela vous facilitera grandement la vie.
En fait, j'ai rencontré un problème dans lequel je devais définir winsock2.h comme étant le premier élément include. J'espère que cela sera utile à quelqu'un qui rencontre le même problème, pas seulement Windows.h, mais tout le monde.