1

このコードをxlC8.0(AIX 5.3上)でコンパイルすると、間違った結果が生成されます。印刷する必要があります12345が、代わりにを印刷し804399880ます。constの前を削除するresultと、コードが正しく機能します。

バグはどこにありますか?

#include <stdio.h>
#include <stdlib.h>
#include <string>

long int foo(std::string input)
{
        return strtol(input.c_str(), NULL, 0);
}

void bar()
{
        const long int result = foo("12345");
        printf("%u\n", result);
}

int
main()
{
        bar();
        return 0;
}

コンパイルコマンド:

/usr/vacpp/bin/xlC example.cpp -g

編集:上記のprintfフォーマット文字列を "%ld\n"に変更しても効果はありません。編集2:使用されたAIXバージョンは6.1ではなく5.3でした。

4

5 に答える 5

3

xlC 10.0は正常に動作し、コンパイラのバグのようです

于 2010-04-15T13:00:33.583 に答える
2

これはc++とタグ付けされているので、printfの代わりにcoutを使用するとどうなりますか?

問題は、printfにunsigned intを印刷するように指示してから、実際に印刷するためにsignedlongintを送信しているようです。ほとんどの場合、メモリレイアウトが異なり、printfは実際に何をしたいのか理解できません。

于 2010-04-15T13:39:03.397 に答える
1

なぜ const が重要なのかは少し推測になりますが、合理的な仮定を立てることができます。

resultレジスタに割り当てたり、スタックに置くことができるなど、ブロック スコープを持つ変数。レジスターが使用されるかどうかに影響を与える要因は多数あります。constこの場合、それが問題になる可能性は十分にあります。最終的に、最適と思われるものを使用するのはコンパイラーの権利です。

同様に、関数への引数は、レジスタまたはスタックで渡すことができます。多くの場合、関数は個別にコンパイルされるため、それらのインターフェイス (つまり、宣言) によって、どの引数がどこに行くかが決まります。printf(...) は特殊なケースで、さまざまな型の引数で呼び出すことができます。その結果、どのデータがどこに到達するかが異なり、何を期待するかを printf(...) に伝える必要があります。

変数を関数に渡すとき、コンパイラは通常それをコピーする必要があります。レジスターからスタックへ、あるレジスターから別のレジスターへなど、かなりの数のバリエーションが可能です。指摘したように、ソースの場所は の有無によって異なる場合がありconstます。

たまたま間違った書式指定子を にprintf(...)、つまり%uの代わりに渡しています%ld。これにより、printf(...) がデータを取得するために間違った場所 (おそらくスタックではなくレジスター、またはその逆) を検索する可能性があります。このようなアクションは、非常に驚​​くべき結果を引き起こす可能性があります。たとえば、コピーされていない、またはいくつかのレジスタのランダムな古い値にprintf(...)出くわす可能性があります。result非 const の場合は正しい値が見つかったようですが (間違った場所で見つかった可能性があります)、const の場合printf(...)はゴミが見つかるだけです。

于 2010-04-15T13:46:09.127 に答える
0

おそらく関係ありませんが、注意してください: printf の %u 指定子は符号なし整数を示していますが、符号付き整数を渡しています。

于 2010-04-15T13:04:41.087 に答える
0

g++ はこれを問題なく処理し、警告については言及しません。それはprintfについて不平を言います。long int には %lu を使用する必要があります。または、%ld を使用するか、(unsigned long int) にキャストすることをお勧めします。

于 2010-04-15T13:07:10.103 に答える