Мне определили структуру в заголовке следующим образом:
#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 все правильны и значимы.
Ваш компоновщик может просто выбросить символы, которые, по его мнению, не используются (компоновщик GNU делает это). В этом случае вы можете явно связать объектный файл с этим символом.
В C ++ вы не можете контролировать порядок инициализации глобальных объектов, определенных в других модулях компиляции, без каких-либо дополнительных усилий (см. http://www.parashift.com/c++-faq-lite/ctors.html# faq-10.12 ).
Используйте идиому «построить при первом использовании», что означает просто обернуть статический объект внутри функции.
Если у вас есть:
// 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 ++.
+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