3

ある時点で長いデータ型が int データ型にリファクタリングされたレガシー コードがいくつかあります。このリファクタリング中に、多くの printf / sprintf フォーマット ステートメントが、%d に変更されずに %ld として正しく残されていました。例えば:

int iExample = 32;
char buf[200];

sprintf(buf, "Example: %ld", iExample);

このコードは、GCC と VS2012 コンパイラの両方でコンパイルされます。私たちは静的コード分析に Coverity を使用し、例のようなコードは重大度が中レベルの「Printf 引数タイプの不一致」としてフラグが付けられまし 。フォーマット文字列は、unsigned int 型またはこれらの行に沿った何かを持つ符号付き (%d) の文字列でした。

sprintf などの '_s' バージョンの方が安全であり、上記のコードは std::stringstream などを使用するようにリファクタリングできることも認識しています。ただし、これはレガシー コードです...

上記のコードは、少なくとも %d を使用するか、代わりに std::stringstream のようなものを使用するようにリファクタリングする必要があることに同意します。

好奇心から、上記のコードが間違った結果を生成する状況はありますか? このレガシー コードはかなり前から存在しており、正常に動作しているようです。

更新しました

  • STL という単語の使用を削除し、std::stringstream に変更しました。
4

2 に答える 2

4

標準に関する限り、動作は定義されていません。つまり、標準は何が起こるかについてまったく何も述べていません。

実際には、intlongが同じサイズと表現を持っている場合、「動作」する可能性が非常に高くなります。つまり、正しいフォーマット文字列が使用されているかのように動作します。(32 ビット システムでは と の両方で 32 ビットになるのが一般的intですlong)。

longが よりも広い場合でもint、「正しく」動作する可能性があります。たとえば、呼び出し規則は、両方の型が同じレジスタに渡される、または両方が同じサイズのマシンの「ワード」としてスタックにプッシュされるようなものである可能性があります。

または、恣意的に悪い方法で失敗する可能性があります。intが 32 ビットで64 ビットの場合、オブジェクトを読み取ろうとするlongのコードは、渡された実際の 32 ビットと 32 ビットのガベージを組み合わせた 64 ビット オブジェクトを取得する可能性があります。または、余分な 32 ビットが一貫してゼロである可能性がありますが、32 の有効ビットが 64 ビット オブジェクトの間違った端にあります。また、32 ビットのみが渡されたときに 64 ビットをフェッチすると、他の引数で問題が発生する可能性があることも考えられます。の正しい値が得られる可能性がありますが、次の引数が間違ったスタック オフセットからフェッチされる可能性があります。printflongintiExample

私のアドバイス: 正しいフォーマット文字列を使用するようにコードを修正する必要があります (そして、問題のある呼び出しを検出するためのツールがあります)。また、(関心のあるすべての C 実装で) テストを行って、目に見える症状が発生するかどうかを確認してください。実際には。テストの結果は、問題を修正するかどうかを決定するためではなく、問題を修正する優先順位を決定するためにのみ使用する必要があります。コードが明らかに失敗している場合は、今すぐ修正する必要があります。そうでない場合は、後で待つことで問題を解決できます (おそらく他に取り組むべきことがあります)。

于 2015-03-20T19:02:12.733 に答える
1

これは未定義であり、実装に依存します。int と long が同じサイズの実装では、期待どおりに動作する可能性があります。しかし、32 ビットの int と 64 ビットの long を持つ任意のシステムで試してみてください。特に、整数が最後の format 引数ではない場合、printf が 32 ビットしか提供されていないのに 64 ビットを読み取るという問題が発生する可能性があります。おそらくガベージであり、アラインメントによっては、次の引数にも正しくアクセスできない可能性があります。

于 2015-03-20T17:09:17.940 に答える