1

私が取り組んでいるやや大規模なプロジェクトがあり、誰かがこれに似たコードを追加したことを発見しました:

std::cout << std::hex << variable << endl;

すべての cout 呼び出しを調べて、それぞれを手動で調べる以外に、出力ストリームのベースを 16 進数として残した問題のある cout 行を特定する方法はありますか?

ベースを設定するにはさまざまな方法があるようで、単一の関数呼び出しにブレークポイントを設定してもうまくいかないようです。例えば:

  • ... << std::hex << ...
  • ... << setbase(16) << ...
  • std::cout.setf ( std::ios::hex, std::ios::basefield );

データブレークポイントを設定できるように、libstdc ++が内部変数を格納するために使用している変数を簡単に知る方法はありますか?

アップデート:

コードをいじってみたところ、perreal と Employed Russian からの両方の回答を部分的に使用して、最終的に解決策を思いつくことができました。これが私がしたことです:

まず、プログラム内に次のコードを追加して、ブレークして関数にステップインし、cout フラグ変数 (_M_flags) のアドレスを取得できるようにしました。

std::ios_base::fmtflags f;
f = std::cout.flags();

2 行目にブレークポイントを設定し、関数にステップインすると、次の libstdc++ コードが得られました。

// [27.4.2.2] fmtflags state functions
/**
 *  @brief  Access to format flags.
 *  @return  The format control flags for both input and output
 */
fmtflags
flags() const
{ return _M_flags; }

残念ながら、gdb はこの変数を出力できませんでしたが、逆アセンブリ ビューに移動することで、_M_flags で使用されているアドレスを特定できました。

 x0x84ca2e8 <std::ios_base::flags() const>                push   %ebp
 x0x84ca2e9 <std::ios_base::flags() const+1>              mov    %esp,%ebp
 x0x84ca2eb <std::ios_base::flags() const+3>              mov    0x8(%ebp),%eax
>x0x84ca2ee <std::ios_base::flags() const+6>              mov    0xc(%eax),%eax 
 x0x84ca2f1 <std::ios_base::flags() const+9>              pop    %ebp
 x0x84ca2f2 <std::ios_base::flags() const+10>             ret

0xc(%eax)_M_flags のアドレスが含まれていました。

アドレスを取得した後、条件付きハードウェア ウォッチポイントを設定して、16 進ビットがいつ変化するかを確認し、問題のあるコードを追跡するのは簡単でした。

実行時に dlopen を介してロードされた .so オブジェクトが原因であることが判明しました。

問題を解決するために、この質問で参照されているように、Boost IO State Savers を使用することになりました。

4

2 に答える 2

2

データブレークポイントを設定できるように、基本変数を格納するためにglibcが内部的に使用している変数を簡単に知る方法はありますか?

いいえ: glibc はライブラリであり、構造体であるCについては何も知りません。あなたの質問はglibc ではなく に関するものです。std::coutC++libstdc++

libstdc++の実装を見ると、 にウォッチポイントを設定する必要があるようですstd::cout._M_os._M_flags。ただし、フラグのさまざまなビットは、出力操作中に何度も設定されるため、ウォッチポイントを_S_hex (== 1<<3 == 8)ビットに基づいて条件付きにすることをお勧めします。

于 2013-05-02T04:31:06.777 に答える
2
#include <iostream>
int main() {
    std::ios_base::fmtflags f;
    f = std::cout.flags();
    std::cout << 21 << std::endl;
    std::cout << (f & std::cout.hex) << std::endl;
    std::cout << std::hex << 21 << std::endl;
    f = std::cout.flags();
    std::cout << (f & std::cout.hex) << std::endl;
    return 0;
}

出力

21
0
15
8

したがってf & std::cout.hex、式として使用するか、そのフラグが に格納されている場所を見つけることができるようstd::coutです。これは実装に依存する可能性があります。

于 2013-05-01T23:53:48.397 に答える