lenguaje - igualar char c++
Error de sÃmbolo duplicado asociado con la declaración const char* (5)
Me encantaría ayudar a diagnosticar el origen de un error de símbolo duplicado que recibo cuando intento compilar con g ++ 4.2.1.
El error específico es
ld: duplicate symbol _SOCIODEM_FILENAMES in /var/folders/c+/c+eq1Qz1Feye7vxs5mQOUE+++TI/-Tmp-//ccP3yVgF.o and /var/folders/c+/c+eq1Qz1Feye7vxs5mQOUE+++TI/-Tmp-//cc1NqtRL.o
collect2: ld returned 1 exit status
El error ocurre solo cuando incluyo esta declaración en un archivo llamado Parameters.h
:
// Parameters.h
#ifndef PARAMETERS_H
#define PARAMETERS_H
// ...[code snipped]...
const int NUM_SOCIODEM_FILES = 5;
const char * SOCIODEM_FILENAMES[ NUM_SOCIODEM_FILES ] = { "LSPAN_PDF.txt",
"FLEDGE_PDF.txt",
"PAIR_PDF.txt",
"BIRTH_AGE_PDF.txt",
"SPLIT_PDF.txt" };
// ...[code snipped]...
#endif
He buscado todos mis archivos, y este es el único lugar donde se declara SOCIODEM_FILENAMES
. Cuando comento la declaración, el error del "símbolo duplicado" desaparece.
No estoy familiarizado con los errores del enlazador (si eso es lo que es) y agradecería ayuda para solucionar el problema. Todos mis archivos de encabezado tienen #ifndef...#define...#endif
wrappers. Mi comando de compilación es
g++ -o a.out -I /Applications/boost_1_42_0/ Host.cpp Simulation.cpp main.cpp Rdraws.cpp
Gracias por adelantado.
Resumen de la solución
Ahora tengo en Parameters.h:
const char * const SOCIODEM_FILENAMES[ NUM_SOCIODEM_FILES ] = { "LSPAN_PDF.txt",
"FLEDGE_PDF.txt",
"PAIR_PDF.txt",
"BIRTH_AGE_PDF.txt",
"SPLIT_PDF.txt" };
Todas las demás definiciones y declaraciones en Parameters.h no se modifican. Andrey y otros comentaristas resumen un enfoque alternativo utilizando extern
, que es excesivo para mis propósitos.
Como otros han sugerido, una forma de hacerlo es declarar NUM_SOCIODEM_FILES
y SOCIODEM_FILENAMES
como extern
y definirlos una vez en un archivo externo. La otra forma es declararlas como static
esto hace que se dupliquen en cada archivo objeto que incluye el encabezado, pero no creará un error ya que la definición es privada para ese archivo objeto. La opción que elijas dependerá de tus preferencias.
El problema es que está poniendo una definición en un archivo de encabezado. Si incluye ese archivo en más de una unidad de compilación (archivo .cpp), estará creando varias definiciones y, en el momento del enlace, obtendrá ese error.
Debe colocar ambas definiciones en un archivo .cpp y colocar solo una declaración en el archivo de encabezado:
extern const int NUM_SOCIODEM_FILES;
extern const char * SOCIODEM_FILENAMES[];
El protector de encabezado ( #ifndef..#endif
wrapper) simplemente evita que incluya el mismo encabezado varias veces en un único archivo fuente. Todavía puede tener varios archivos fuente que incluyen ese encabezado, y cada uno declarará ese símbolo por separado. Dado que todos tienen el mismo nombre, vincular esas fuentes generará una colisión de nombre de símbolo. Probablemente desee declarar el símbolo en un archivo fuente en lugar de un archivo de encabezado
Lo más probable es que esté #include
este archivo en múltiples archivos fuente. El problema es que cada inclusión da como resultado una definición separada para una variable llamada SOCIODEM_FILENAMES
. Incluir guardias no ayuda con esto. Incluir guardias previene múltiples declaraciones dentro de una sola unidad de compilación; no impiden definiciones múltiples en varias unidades de compilación.
Lo que debe hacer es declarar estas variables como extern
en el encabezado, y luego definirlas en exactamente un archivo fuente. p.ej
// Parameters.h
#ifndef PARAMETERS_H
#define PARAMETERS_H
// ...[code snipped]...
extern const int NUM_SOCIODEM_FILES;
extern const char * SOCIODEM_FILENAMES[];
// ...[code snipped]...
#endif
y entonces:
// Parameters.cpp (or some other source file)
const int NUM_SOCIODEM_FILES = 5;
const char * SOCIODEM_FILENAMES[ NUM_SOCIODEM_FILES ] = { "LSPAN_PDF.txt",
"FLEDGE_PDF.txt",
"PAIR_PDF.txt",
"BIRTH_AGE_PDF.txt",
"SPLIT_PDF.txt" };
Puedes salirte con la tuya sin hacer esto para el int
porque es un entero constante, por lo que el compilador solo puede tratarlo como una constante en tiempo de compilación, y nunca aparecerá en el código compilado. Sin embargo, el char*
no se puede tratar de esta manera, por lo que debe tener exactamente una definición (conocida como la "regla de una definición" en C ++).
Por alguna razón, ninguna de las respuestas hasta ahora ha tratado de explicar la diferencia entre su objeto entero NUM_SOCIODEM_FILES
y el objeto de la matriz SOCIODEM_FILENAMES
. Este último desencadena el error del enlazador por las razones ya explicadas: porque incluye su archivo de encabezado en varios archivos de implementación. Sin embargo, el primero se vincularía sin ningún problema (porque de hecho no hay problemas con la declaración NUM_SOCIODEM_FILES
). ¿Por qué?
La razón de esto es que su objeto NUM_SOCIODEM_FILES
se declara const
. En C ++, los objetos const tienen enlaces internos por defecto, lo que significa que no causan problemas de vinculación incluso si están definidos en múltiples archivos de implementación. En otras palabras, en C ++ tu NUM_SOCIODEM_FILES
es equivalente a
static const int NUM_SOCIODEM_FILES = 5; /* internal linkage */
por lo que no conduce a ningún problema de vinculación.
Al mismo tiempo, su SOCIODEM_FILENAMES
no se declara constante, por lo que obtiene enlaces externos por defecto y, finalmente, conduce a errores del enlazador. Pero si declaras tus SOCIODEM_FILENAMES
como const
también, el problema desaparecerá
const char * const SOCIODEM_FILENAMES[ NUM_SOCIODEM_FILES ] = {
...
Tenga en cuenta dónde se coloca la const
adicional en la declaración. Si solo agrega ese const
extra y deja todo lo demás como está (es decir, conserve la definición si SOCIODEM_FILENAMES
en el archivo de encabezado), el vinculador no informará el error, incluso si incluye el archivo de encabezado en varias unidades de traducción.
Sin embargo, este no es un enfoque recomendado, ya que de esa manera le dará a su vinculación interna de SOCIODEM_FILENAMES
y terminará con una copia independiente de la matriz SOCIODEM_FILENAMES
en cada unidad de traducción, algo que podría funcionar bien pero aún tiene muy poco sentido. Por lo tanto, para su matriz, normalmente es mejor usar el enfoque extern
recomendado en otras respuestas.
Sin embargo, tenga en cuenta que normalmente no debería hacerlo para NUM_SOCIODEM_FILES
declaración !!! Está bien tal como está, definido en el archivo de encabezado. A menos que intente hacer algo inusual, las constantes escalares normalmente deberían definirse con el inicializador en los archivos de encabezado, de esa manera se pueden ver como constantes de tiempo de compilación en todas las unidades de traducción, lo cual es algo bastante valioso. Por lo tanto, tenga cuidado con el extraño consejo presente en algunas otras respuestas para mover la definición de NUM_SOCIODEM_FILES
al archivo .cpp
también, esto en realidad no tiene sentido y es una .cpp
totalmente incorrecta.