Почему я получаю segfaults при объявлении структуры глобально или экстерна?

Мне определили структуру в заголовке следующим образом:

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

Который я использую в своем коде как таковом:

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

Это работает. Если однако, объявляю я LC_ERRMSG err; глобально - т.е. вне функции это используется, или даже extern LC_ERRMSG err; (который был моим исходным намерением, поскольку я захочу смочь считать ошибочное состояние в центральной части), код segfaults в вызове snprintf.

Можно ли дать мне какой-либо ключ к разгадке почему?

ddd говорит мне, что память инициализируется, или всему обнуляет, когда он объявляется глобально, или по крайней мере инициализируется и читаем когда заявленный экстерн. Значения szFilename, szError и LC_ERR_LEN все правильны и значимы.

5
задан Cogwheel 1 July 2010 в 13:44
поделиться

3 ответа

Ваш компоновщик может просто выбросить символы, которые, по его мнению, не используются (компоновщик GNU делает это). В этом случае вы можете явно связать объектный файл с этим символом.

В C ++ вы не можете контролировать порядок инициализации глобальных объектов, определенных в других модулях компиляции, без каких-либо дополнительных усилий (см. http://www.parashift.com/c++-faq-lite/ctors.html# faq-10.12 ).

Используйте идиому «построить при первом использовании», что означает просто обернуть статический объект внутри функции.

3
ответ дан 14 December 2019 в 08:40
поделиться

Если у вас есть:

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

и:

// 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);
}

, то это должно сработать. Однако, если вы переключите вторую строку main.cpp на:

extern LC_ERRMSG err;

, тогда вам нужно убедиться, что хранилище для err скомпилировано в один из ваших объектных файлов. Например, вы можете скомпилировать этот источник:

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

LC_ERRMSG err;

и связать полученный globals.o с main.o .

Ни один из подходов не должен вызывать ошибки сегментации. Если вы получаете ошибку сегментации, проблема может заключаться в том, что LC_ERR_LEN имеет другое значение при компиляции globals.cpp , чем при main.cpp компилируется. Или, возможно, szFilename или szError имеют значение NULL / неверно. Семейство printf не может печатать NULL или неверные указатели с флагом формата % s ; следующий код вызывает ошибку сегментации:

#include <stdio.h>

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

РЕДАКТИРОВАТЬ: Я подумал о другой потенциальной причине проблемы. У вас может возникнуть конфликт символов, если вы используете компилятор C, поскольку err - это символ, который может использоваться как имя нескольких разных глобальных переменных в большом проекте. Если вы используете компилятор C ++, то процесс изменения имени должен гарантировать, что каждый err имеет свой собственный символ. Просто убедитесь, что вы компилируете как C ++.

2
ответ дан 14 December 2019 в 08:40
поделиться

+1 за ответ Даниила. Вот работа для меня. Вам подходит? Проголосуйте за ответ Даниэля.


// 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
2
ответ дан 14 December 2019 в 08:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: