2010-07-01 10 views
5

que tienen una estructura definida en un encabezado de la siguiente manera:¿Por qué obtengo segfaults al declarar una estructura de forma global o externa?

#define LC_ERR_LEN 300 
typedef struct dLC_ERRMSG { 
    short nr; 
    short strategy; 
    char tx[LC_ERR_LEN]; 
} LC_ERRMSG; 

que utilizo en mi código como tal:

LC_ERRMSG err; 
char *szError; 
szError = strerror(sStatus); 
snprintf(err.tx,LC_ERR_LEN," %s - %s",szFilename,szError); 
/* do something with our error string */ 

que funciona. Sin embargo, si declaro LC_ERRMSG err; en todo el mundo, es decir, fuera de la función que se utiliza, o incluso extern LC_ERRMSG err; (que era mi intención original, ya que me gustaría poder leer el estado de error en una ubicación central), el código segfaults en el snprintf llamada.

¿Puede darme alguna pista de por qué?

ddd me dice que la memoria se inicializa a todos los ceros cuando se declara globalmente, o al menos se inicializa y se puede leer cuando se declara extern. Los valores szFilename, szError y LC_ERR_LEN son todos correctos y significativos.

+5

Parece C, no C++? –

+1

Y los nombres de las variables parecen un gato caminando por el teclado. –

+2

Es un gato húngaro, y estoy seguro de que el gato de Freakzoid también. – maxwellb

Respuesta

3

Su enlazador puede simplemente tirar a la basura los símbolos, que a su juicio no se utilizan (el enlazador de GNU lo hace) . En este caso, puede vincular explícitamente el archivo objeto con ese símbolo.

Con C++ no puede controlar el orden de inicialización de los objetos globales definidos en otras unidades de compilación sin ningún esfuerzo adicional (consulte http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.12).

Use la expresión "construir en el primer uso", que simplemente significa envolver su objeto estático dentro de una función.

+0

¡Muchas gracias! Eso lo resolvió – relet

2

Si usted tiene:

// structs.hpp 
#define LC_ERR_LEN 300 
typedef struct dLC_ERRMSG { 
    short nr; 
    short strategy; 
    char tx[LC_ERR_LEN]; 
} LC_ERRMSG; 

y:

// main.cpp 
#include "structs.hpp" 
LC_ERRMSG err; 

int main() 
{ 
    // ... 

    char *szError; 
    szError = strerror(sStatus); 
    snprintf(err.tx, LC_ERR_LEN, "%s - %s", szFilename, szError); 
} 

entonces esto debería funcionar. Sin embargo, si se cambia la segunda línea de main.cpp a:

extern LC_ERRMSG err; 

entonces usted necesita para asegurarse de que el almacenamiento para err se compila en una de sus ficheros objeto. Por ejemplo, se puede compilar esta fuente:

// globals.cpp 
#include "structs.hpp" 

LC_ERRMSG err; 

y vincular el globals.o resultante en main.o.

Cualquiera de los enfoques no debe causar un error de segmentación. Si obtiene un error de segmentación, entonces el problema podría ser que LC_ERR_LEN tiene un valor diferente cuando se compila globals.cpp que cuando se está compilando main.cpp. O bien, quizás szFilename o szError son NULL/malo. La familia printf no puede imprimir NULL o punteros incorrectos con el indicador de formato %s; el siguiente código provoca un fallo de segmentación:

#include <stdio.h> 

int main() 
{ 
    printf("%s\n", NULL); 
} 

EDIT: pensé en otra causa potencial del problema. Podría tener un choque de símbolo si está utilizando un compilador de C ya que err es un símbolo que podría estar en uso como el nombre de varias variables globales diferentes en un proyecto grande. Si está utilizando un compilador de C++, el proceso de creación de nombres debe garantizar que cada err tenga su propio símbolo. Solo asegúrese de que está compilando como C++.

+0

Gracias por su respuesta y maxwellb's. El worksforme maxwellb publicado es prácticamente el mismo que tenía originalmente en mi código, antes de intentar reducir el problema declarando "err" en otro lugar. Estoy compilando como C++ con g ++ también. Sin suerte hasta ahora. Lo que me sorprende es que no tengo idea de cómo err.tx podría corromperse, incluso si hubiera algún otro código usándolo mientras tanto. No está asignado dinámicamente, por lo que podría haberlo liberado accidentalmente. – relet

+0

Usando su depurador, ¿podría verificar que 'szFilename' y' szError' no son '' SNULL' en la línea 'snprintf' y que' szFilename' está correctamente cerrado? Además, ¿cuál es la dirección 'err.tx'? –

2

+1 por la respuesta de Daniel. Aquí hay un trabajo para mí. ¿Funciona para ti? Voten la respuesta de Daniel.


// structs.hpp 
#define LC_ERR_LEN 300 
typedef struct dLC_ERRMSG { 
    short nr; 
    short strategy; 
    char tx[LC_ERR_LEN]; 
} LC_ERRMSG; 

// error.cpp 
#include "structs.hpp" 

LC_ERRMSG err; 

// main.cpp 
#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 
#include "structs.hpp" 
extern LC_ERRMSG err; 

int main() 
{ 
    // ... 
    char *szFilename = "EXAMPLE.LOG"; 
    int sStatus = 0; 
    char *szError; 
    szError = strerror(sStatus); 
    snprintf(err.tx, LC_ERR_LEN, "%s - %s", szFilename, szError); 

    printf("err.tx: %s", err.tx); 
} 

// Output: 
err.tx: EXAMPLE.LOG - No error 
Cuestiones relacionadas