1

addr addr 33 44addr がどこにでもあり、両方が同じであることを期待しています。

gccでそれを取得します。しかし、MSVCで私は得る

8D3678 0 9257096 9257096
8D3678 0 9257104 9257104
8D3678 0 9257112 9257112

なんと!?! 警告/エラーは表示されません。最後の 2 つの値が 33 44 ではない理由と、それらが同じである (そして非常に間違っている) 理由を説明したい人はいますか?

#include <cstdio>
#include <vector>
class Person{
public:
    int age;
    int weight;
    Person(int age, int weight):age(age), weight(weight){}
};
int main() {
    std::vector<Person> ls;
    Person p(33, 44);
    ls.push_back(p);
    ls.push_back(p);
    ls.push_back(p);
    for(auto i=ls.begin();i!=ls.end();++i){
        printf("%X %X %d %d\n", i, &(*i), (*i).age, (*i).weight);
    }

}
4

3 に答える 3

8

整数が期待される引数vector::iteratorとして aを渡しています。printfこれにより、未定義の動作が発生します。(ちなみに、2 番目の引数としてポインターを渡す場合も同様です。ただし、これにより、32 ビット プラットフォームで期待する結果が得られる可能性があります)。printfは型チェックされていないため、通常は代わりに C++ スタイルの I/O を使用する必要があります。

GCC の実装は単なるポインターのラッパーであるため、意図した結果が誤って得られます。MSVC の実装はより大きな型のようです。確かに、デバッグ ビルドでは、実行時の有効性チェックをサポートするために、イテレータはそのプラットフォーム上で非常に大きくなっています。

警告/エラーが表示されない

これは、それらを有効にしていないためです。gcc で-Wall(または単に-Wformat) を使用すると、次のようになります。

test.cpp:16:72: warning: format ‘%X’ expects argument of type ‘unsigned int’, but argument 2 has type ‘__gnu_cxx::__normal_iterator<Person*, std::vector<Person> >’ [-Wformat]
test.cpp:16:72: warning: format ‘%X’ expects argument of type ‘unsigned int’, but argument 3 has type ‘Person*’ [-Wformat]

何が悪いのか正確に教えてください。

于 2013-06-17T18:18:37.880 に答える
7

イテレータ (std::vector<Person>::iteratorに引数として渡す を含むprintf()) はPOD であることが保証されておらず、C スタイルの可変引数関数への引数は POD のみにすることができます。

なんと!?! 警告/エラーが表示されない

これは、POD 以外の引数を C スタイルの可変引数関数に渡すことが 未定義の動作であるためです。コンパイラは診断を発行する必要はありませんが、一部の非常に優れたコンパイラはそれを実行します (コメントで Mark B が正しく述べているように)。

于 2013-06-17T18:17:58.217 に答える
1

"%X"書式指定子を使用して反復子を書式設定します。を使用してイテレータを「スマート化」します&*

gcc では、ベクターの反復子は通常、ポインターのラッパーであり、同じサイズとレイアウトを持ちます。これが、イテレータを渡してそれを回避できる理由ですprintf

デバッグ モードの MSVC では、1 つ以上のポインターを含むデバッグ イテレーターが使用され、それらのサイズとレイアウトは同じではありません。これが、デバッグ モードで MSVC を使用するとコードが壊れる理由です。

于 2013-06-17T18:18:05.807 に答える