5

C++ に厄介なバグがありました。したがって、構造体にラップされたレジスタと値のリストがあり、それらの構造体は配列で初期化されます。しかし、誤って .()の代わりに入力してしまいました{}。ここにいくつかのテストコードがあります:

#include <stdio.h>

struct reg_val {
        unsigned reg;
        unsigned val;
};

struct reg_val faulty_array[] = { 
        {0x5001, 0xff},
        {0x5580, 0x01},
        (0x5580, 0x02), //<- THIS LINE IS THE PROBLEM
        (0x5589, 0x00), //<- AND THIS LINE
};

struct reg_val good_array[] = { 
        {0x5001, 0xff}, 
        {0x5580, 0x01}, 
        {0x5580, 0x02},
        {0x5589, 0x00},
};

int main()
{
        unsigned i;
        unsigned faulty_size = sizeof(faulty_array) / sizeof(struct reg_val);
        printf("Size of faulty array: %d\n", faulty_size);

        for (i = 0; i < faulty_size; ++i) {
                printf("faulty reg: %x  val: %x\n", faulty_array[i].reg,
                       faulty_array[i].val);
        }   

        unsigned good_size = sizeof(good_array) / sizeof(struct reg_val);
        printf("\nSize of good array: %d\n", good_size);
        for (i = 0; i < good_size; ++i) {
                printf("good reg: %x  val: %x\n", good_array[i].reg,
                       good_array[i].val);
        }   
        return 0;
}

私は C に慣れていますが、驚いたことに、これはまだ g++ でコンパイルされています。

$ g++ -Wall array.cc
array.cc:11: warning: left-hand operand of comma has no effect
array.cc:12: warning: left-hand operand of comma has no effect
array.cc:13: warning: missing braces around initializer for ‘reg_val’
$ ./a.out 
Size of faulty array: 3
faulty reg: 5001  val: ff
faulty reg: 5580  val: 1
faulty reg: 2  val: 0       <-- the first value gets discarded as mentioned in the compiler warning

Size of good array: 4
good reg: 5001  val: ff
good reg: 5580  val: 1
good reg: 5580  val: 2
good reg: 5589  val: 0

このコードは明らかに C コンパイラでのコンパイルに失敗します。C++ コンパイラが (しぶしぶではありますが) このコードを受け入れさせる C++ の違いは何ですか?

4

3 に答える 3

4

あなたの質問に答えるために、私は最初に答えます: なぜこれは C でコンパイルできないのですか? さて、次の理由でコンパイルに失敗します。

initializer element is not constant

{}適切な測定のために、 C から s を削除しましょう:

struct reg_val faulty_array[] = { 
        {0x5001, 0xff},
        {0x5580, 0x01},
        0x5580, 0x02, //<- THIS LINE IS THE PROBLEM
        0x5589, 0x00, //<- AND THIS LINE
};

プログラムは次のように出力します。

Size of faulty array: 4
faulty reg: 5001  val: ff
faulty reg: 5580  val: 1
faulty reg: 5580  val: 2
faulty reg: 5589  val: 0

これは、C 標準 (および C++) で完全に許可されています。C (および C++) は、構造体の要素を初期化するためにブレースを平坦化します (これは戻ってきます)。C でコードが失敗するのは、静的記憶域期間を持つオブジェクトは、定数式または定数式を含む集約初期化子で初期化する必要があるためです。(0x5580, 0x02)C は定数式として扱いません。

これは (残念ながら) C++ でコンパイルされます。C++ は 2 つの定数式の間のコンマ演算子を定数式として扱うため、コードは次のようになります。

struct reg_val faulty_array[] = { 
        {0x5001, 0xff},
        {0x5580, 0x01},
        0x02,
        0x00,
};

・・・もちろん許されます。

struct reg_val faulty_array[] = { 
        {0x5001, 0xff},
        {0x5580, 0x01},
        {0x02, 0x00},
};
于 2012-07-19T16:36:57.913 に答える
4

C でコンパイルできないと思う理由は何ですか?

C++: http://ideone.com/KLPh4 C: http://ideone.com/VYUbL

警告に注意してください。 私はこれを十分に強調することはできません。このような間違いを見つけるのに役立つ警告があります。

C のエラー メッセージは、その違いを完全に明確にしています。C では、イニシャライザは任意の式ではなく、定数である必要があります。これはCで正常にコンパイルされるため、これらが定数と見なされない理由は私には意味がありません:

于 2012-07-19T16:19:57.147 に答える
3

C++ には、両方のオペランドを評価し、左側を無視して右側のオペランドの値を返すコンマ演算子があります。ここでもっとはっきりと見ることができます。

そして C も、どうやら =) (ありがとう、@BenVoigt)

于 2012-07-19T16:19:12.643 に答える