为什么在全局或外部声明结构时会出现段错误?

发布于 2024-09-08 00:38:07 字数 623 浏览 1 评论 0原文

我在标头中定义了一个结构,如下所示:

#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 都是正确且有意义的。

I have a struct defined in a header as follows:

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

Which I use in my code as such:

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

That works. If however, I declare LC_ERRMSG err; globally - i.e. outside the function it is used, or even extern LC_ERRMSG err; (which was my original intention, as I would want to be able to read out the error status in a central location), the code segfaults at the snprintf call.

Can you give me any clues why?

ddd tells me that the memory is initialized to either all zeroes when declared globally, or at least initialized and readable when declared extern. The values szFilename, szError and LC_ERR_LEN are all correct and meaningful.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

葮薆情 2024-09-15 00:38:07

你的链接器可以简单地丢弃它认为没有使用的符号(GNU 链接器就是这样做的)。在这种情况下,您可以将目标文件与该符号显式链接。

使用 C++,您无法控制在其他编译单元中定义的全局对象的初始化顺序,无需任何额外的努力(请参阅 http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.12)。

使用“首次使用时构造”习惯用法,这只是意味着将静态对象包装在函数内。

Your linker can simply throw away the symbols, which it believes are not used (the GNU linker does so). In this case you can explicitly link the object file with that symbol.

With C++ you can not control the order of initialization of global objects defined in other compilation units without any additional efforts (see http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.12).

Use the "construct on first use" idiom, which simply means to wrap your static object inside a function.

平安喜乐 2024-09-15 00:38:07

如果你有:

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

任何一种方法都不应导致分段错误。如果您遇到分段错误,则问题可能是编译 globals.cppLC_ERR_LEN 的值与编译 main.cpp 时的值不同。 code> 正在编译。或者,szFilenameszError 可能是 NULL/bad。 printf 系列无法打印 NULL 或带有格式标志 %s 的错误指针;以下代码会导致分段错误:

#include <stdio.h>

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

编辑:我想到了问题的另一个潜在原因。如果您使用 C 编译器,则可能会发生符号冲突,因为 err 是一个可以用作大型项目中多个不同全局变量的名称的符号。如果您使用的是 C++ 编译器,则名称修改过程应确保每个 err 都有自己的符号。只要确保您正在编译为 C++ 即可。

If you have:

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

and:

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

then this should work. However, if you switch the second line of main.cpp to:

extern LC_ERRMSG err;

then you need to make sure that the storage for err is compiled into one of your object files. For example, you could compile this source:

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

LC_ERRMSG err;

and link the resulting globals.o into main.o.

Either of the approaches should not cause a segmentation fault. If you are getting a segmentation fault, then the problem could be that LC_ERR_LEN has a different value when globals.cpp is being compiled than when main.cpp is being compiled. Or, perhaps szFilename or szError are NULL/bad. The printf family cannot print NULL or bad pointers with format flag %s; the following code causes a segmentation fault:

#include <stdio.h>

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

EDIT: I thought of another potential cause of the problem. You could have a symbol clash if you are using a C compiler as err is a symbol that could be in use as the name of several, different global variables in a large project. If you are using a C++ compiler, then the name mangling process should ensure that each err has its own symbol. Just make sure that you are compiling as C++.

负佳期 2024-09-15 00:38:07

丹尼尔的回答+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

+1 for Daniel's Answer. Here's a Works-for-me. Works for you? Upvote Daniel's answer.


// 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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文