6

次のようにヘッダーで定義された構造体があります。

#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 はすべて正しく、意味があります。

4

3 に答える 3

3

リンカーは、使用されていないと思われるシンボルを単純に破棄できます (GNU リンカーはそうします)。この場合、オブジェクト ファイルをそのシンボルに明示的にリンクできます。

C++ では、他のコンパイル単位で定義されたグローバル オブジェクトの初期化の順序を制御することはできません ( http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.12を参照)。

"construct on first use" イディオムを使用します。これは単に、静的オブジェクトを関数内にラップすることを意味します。

于 2010-07-01T18:04:34.710 に答える
2

あなたが持っている場合:

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

その後、これは機能するはずです。ただし、の2行目を次のように切り替えると次のようになりますmain.cpp

extern LC_ERRMSG err;

err次に、のストレージがオブジェクトファイルの1つにコンパイルされていることを確認する必要があります。たとえば、次のソースをコンパイルできます。

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

LC_ERRMSG err;

globals.o結果をにリンクしmain.oます。

どちらのアプローチでも、セグメンテーション違反が発生することはありません。セグメンテーション違反が発生している場合は、コンパイル時とコンパイルLC_ERR_LEN時の値が異なることが問題である可能性があります。または、おそらくまたは/badです。ファミリは、フォーマットフラグを使用してポインタを出力したり不正なポインタを出力したりすることはできません。次のコードにより、セグメンテーション違反が発生します。globals.cppmain.cppszFilenameszErrorNULLprintfNULL%s

#include <stdio.h>

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

編集:私は問題の別の潜在的な原因を考えました。err大規模なプロジェクトでいくつかの異なるグローバル変数の名前として使用される可能性のあるシンボルとしてCコンパイラを使用している場合、シンボルが衝突する可能性があります。C ++コンパイラを使用している場合、名前マングリングプロセスでは、それぞれerrに独自のシンボルがあることを確認する必要があります。C++としてコンパイルしていることを確認してください。

于 2010-07-01T13:58:32.480 に答える
2

ダニエルの回答に+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
于 2010-07-01T14:21:54.033 に答える