c++ - class h and class cpp
Archivos de encabezado de redefinición de C++(winsock2.h) (15)
Ah, la fealdad de Windows ... El orden de los incluidos es importante aquí. Debe incluir winsock2.h antes de windows.h. Dado que windows.h probablemente se incluye desde su encabezado precompilado (stdafx.h), deberá incluir winsock2.h desde allí:
#include <winsock2.h>
#include <windows.h>
¿Cómo evito incluir archivos de encabezado dos veces? El problema es que estoy incluyendo el en MyClass.h y luego incluyo MyClass.h en muchos archivos, por lo que incluye varias veces y se produce un error de redefinición. ¿Como prevenir?
Estoy usando #pragma una vez en vez de incluir guardias, y supongo que está bien.
MyClass.h:
// MyClass.h
#pragma once
#include <winsock2.h>
class MyClass
{
// methods
public:
MyClass(unsigned short port);
virtual ~MyClass(void);
};
EDITAR: Algunos de los errores que obtengo
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''
Al usar "guardias de encabezado":
#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
Como otros sugirieron, el problema es cuando se incluye windows.h
antes de WinSock2.h
. Porque windows.h
incluye winsock.h
. No puede usar tanto WinSock2.h
winsock.h
.
Soluciones:
Incluya
WinSock2.h
antes dewindows.h
. En el caso de encabezados precompilados, debe resolverlo allí. En el caso del proyecto simple, es fácil. Sin embargo, en proyectos grandes (especialmente cuando se escribe código portátil, sin encabezados precompilados) puede ser muy difícil, porque cuando se incluye su encabezado conWinSock2.h
,windows.h
ya puede estar incluido desde algún otro archivo de cabecera / implementación.Defina
WIN32_LEAN_AND_MEAN
antes dewindows.h
o proyecto de ancho. Pero excluirá muchas otras cosas que pueda necesitar y debe incluirlas por su cuenta.Defina
_WINSOCKAPI_
antes dewindows.h
o proyecto de ancho. Pero cuando incluyeWinSock2.h
obtiene una advertencia de redefinición de macros.Use
windows.h
lugar deWinSock2.h
cuandowinsock.h
sea suficiente para su proyecto (en la mayoría de los casos lo es). Esto probablemente dará como resultado un tiempo de compilación más largo pero resuelve cualquier error / advertencia.
Debe usar protector de encabezado.
poner esas líneas en la parte superior del archivo de encabezado
#ifndef PATH_FILENAME_H
#define PATH_FILENAME_H
y en la parte inferior
#endif
En VS 2015, lo siguiente funcionará:
#define _WINSOCKAPI_
Mientras que lo siguiente no:
#define WIN32_LEAN_AND_MEAN
En mi proyecto (uso VS 2008 SP1) funciona la siguiente solución:
Archivo de cabecera:
//myclass.h
#pragma once
#define _WINSOCKAPI_
#include <windows.h>
Clase Cpp:
//myclass.cpp
#include "Util.h"
#include "winsock2class.h"
#pragma comment(lib, "Ws2_32.lib")
donde #include "winsock2class.h" significa clase que implementó winsock2.h:
//winsock2class.h
#include <winsock2.h>
#include <windows.h>
#pragma comment(lib, "Ws2_32.lib")
Encontré este enlace this que tiene una alternativa que me fue muy this :
#define _WINSOCKAPI_ // stops windows.h including winsock.h
#include <windows.h>
#include <winsock2.h>
Estaba teniendo problemas para encontrar dónde ocurrió el problema, pero al agregar que #define pude construir sin resolverlo.
Este problema se produce cuando se incluye <windows.h>
antes de <winsock2.h>
. Intente organizar su lista de inclusión que <windows.h>
se incluye después de <winsock2.h>
o defina _WINSOCKAPI_
primero:
#define _WINSOCKAPI_ // stops windows.h including winsock.h
#include <windows.h>
// ...
#include "MyClass.h" // Which includes <winsock2.h>
Ver también this
Me encontré con el mismo problema y aquí está lo que he descubierto hasta ahora:
De este fragmento de salida -
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''
- Parece que tanto ws2def.h como winsock.h han sido incluidos en su solución.
Si miras el archivo ws2def.h, comienza con el siguiente comentario:
/*++
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
--*/
Preste atención a la última línea: "Este archivo no puede ser incluido por un módulo que también incluya WINSOCK.H"
Todavía estoy tratando de rectificar el problema sin hacer cambios en el código.
Avísame si esto tiene sentido.
Me encontré con este problema cuando traté de extraer un paquete de un tercero que aparentemente incluía Windows.h en algún lugar en su desorden de encabezados. Definir _WINSOCKAPI_
a nivel de proyecto fue mucho más fácil (por no mencionar que más fácil de mantener) que vadear su sopa y solucionar la problemática incluyen.
No usaría solo FILENAME_H, pero
#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
Siempre he usado una guía de postfix. Encontré una base de código muy pobre hace algunos años que tenía diferentes archivos de encabezado con el mismo nombre de archivo e incluye guard. Los archivos en cuestión habían definido una clase con el mismo nombre. Si solo se usaran espacios de nombres. Algunos proyectos compilados algunos no lo hicieron. El uso de guardias únicos fue parte de la solución al diferenciar los encabezados y sus contenidos.
En Windows con Visual Studio use guidgen.exe, en Linux uuidgen -t.
Revisé el recursivo incluye, vi los archivos de encabezado que incluyen (recursivamente) algunos #include "windows.h"
y "#include" Winsock.h " and write a
#include" Winsock2.h " . in this files, i added
#include "Winsock2.h" `como el primer include.
Solo una cuestión de paciencia, mira incluye uno por uno y establece este orden, primero #include "Winsock2.h"
luego #include "windows.h"
#incluir guardias es la forma estándar de hacer esto. #pragma una vez no lo es, lo que significa que no todos los compiladores lo admiten.
#pragma once
es escaso, incluso en compiladores de MS, y no es compatible con muchos otros compiladores. Como muchas otras personas han mencionado, usar incluir guardias es el camino a seguir. No uses #pragma once
, te hará la vida mucho más fácil.
#pragma once
se basa en la ruta completa del nombre de archivo. Entonces, lo que probablemente tenga es que hay dos copias idénticas de MyClass.ho Winsock2.h en directorios diferentes.