Почему я получаю ошибки при объявлении структуры глобально или extern? - PullRequest
5 голосов
/ 01 июля 2010

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

#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; (что было моим первоначальным намерением, поскольку я хотел бы иметь возможность считывать статус ошибки в центральном местоположении), ошибки кода при вызове snprintf.

Можете ли вы дать мне какие-либо подсказки, почему?

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

Ответы [ 3 ]

3 голосов
/ 01 июля 2010

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

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

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

2 голосов
/ 01 июля 2010

+ 1 за ответ Даниила. Вот работает для меня. У тебя работает? Upvote ответ Даниила.


// 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 голосов
/ 01 июля 2010

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

// 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 ++.

...