9

表示できる小さなプログラムでこの問題を再現することはできないため、スクリーンショットを使用して質問を説明します。

ユニオンとユニオンの静的メンバーを宣言するクラスがあります。

class 
{ 
/* rest of the class */

    union EmptyString
    {
      char8   m_Empty8[1];
      uchar8  m_EmptyU8[1];
      char32  m_Empty32[1];
    };

    static const EmptyString sm_emptyString;
};

  // Definition
  template <typename T>
  const typename StringBase<T>::EmptyString 
    StringBase<T>::sm_emptyString = { 0 };

次に、文字列のアドレスを返す関数があります。デバッグの目的でaddress、ウォッチ ウィンドウに追加できるように変数を追加しました。関数は次のとおりです (Tここchar8char8は、 の typedef ですchar)。

  template <typename T>
  const char8* StringBase<T>::GetEmptyString( char8 )
  {
    const char8* address = sm_emptyString.m_Empty8;
    //const char8* address = &(sm_emptyString.m_Empty8[0]);
    return address;
    //return sm_emptyString.m_Empty8;
  }

ご覧のとおり、最初は 1 つの return ステートメントがありましたが、スニペットをデバッグできるようにコメントアウトしました。コメントアウトされている他の行は、配列の最初の (そして唯一の) 要素のアドレスを取得しています。このコメントアウトされた行は、その前の行と同じことを行います: const char8* address = sm_emptyString.m_Empty8;.

上記の関数で正しいアドレスを取得していないため、プログラムがクラッシュし、困惑しました。以下では、デバッグ セッションのスクリーンショットを開始します。

アドレス取得前にブレーク

上記では、アドレスがポインターにコピーされる直前にブレークしていることがわかります。以下は、このブレークでのsm_emptyStringとのウォッチ ウィンドウの値です。address

ここに画像の説明を入力

これまでのところ、特別なことは何もありません。以下は、1 行のコードをステップ オーバーした後のスクリーンショットです。

ここに画像の説明を入力

対応するウォッチ ウィンドウ:

ここに画像の説明を入力

ご覧のとおり、コピー先の値addressが間違っています。注意すべきもう 1 つの点は、この関数が数回呼び出され、静的変数アドレスのコピーaddressが正しいことです。アドレスが正しくなく、関数によって返されると、プログラムがクラッシュします (プログラムの後半でアドレスに関する仮定が行われるため)。

ここで何が起きてるの?どこかにメモリを上書きしていますか?これをデバッグするにはどうすればよいですか?

編集:

逆アセンブリ (デバッガによると、のアドレスは でsm_emptyStringあり129F184、逆アセンブリが示すものとは異なります128F134):

template <typename T>
  const char8* StringBase<T>::GetEmptyString( char8 )
  {
0119B850  push        ebp  
0119B851  mov         ebp,esp 
0119B853  push        ecx  
0119B854  mov         dword ptr [ebp-4],0CCCCCCCCh 
    const char8* address = sm_emptyString.m_Empty8;
0119B85B  mov         dword ptr [address],offset StringBase<char>::sm_emptyString (128F134h) 
    //const char8* address = &(sm_emptyString.m_Empty8[0]);
    return address;
0119B862  mov         eax,dword ptr [address] 
    //return sm_emptyString.m_Empty8;
  }

私が使用しているもの: Windows 7、VC++ 2008、デバッグ ビルド

4

1 に答える 1

2

関数を使用しますか?必要な空の文字列は、StringBase<T>その状態やテンプレート引数とは関係ありません。

inline const char8* GetEmptyString( char8 )     
{
    static const char8 address[1] = {0};
    return address;
}

編集:コードが使用するようなユニオンの使用が間違っていることをお勧めします。C99標準が言ういくつかのこと:

  • 6.2.5p20、ユニオンには重複するメンバー オブジェクトのセットがあります
  • 6.7.2.1p14、最大で 1 つのメンバーの値をいつでも共用体オブジェクトに格納できます
  • 附属書 J.1 に格納された最後のもの以外の共用体メンバーの値は指定されていません。

同じことが C++ にも当てはまりますが、現在は標準が手元にありません。そのため、ユニオンを使用して 3 つの文字列を同時に同じ場所に格納することはできません。実際に何が問題を引き起こしているのかはわかりませんが、まったく別の場所にある可能性が高いため、そのような疑わしい構造を取り除く必要があります。

于 2012-09-24T00:51:50.440 に答える