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.
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.
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++.
+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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With