3

C99 では、構造体の指定された初期化子の概念が導入されました。たとえば、次のようになります。

typedef struct {
    int c;
    char a;
    float b;
} X;

私は次のように初期化することができX foo = {.a = '\1', .b = 2.0F, .c = 4};、呼び出し:printf("c = %d\na = %hhu\nb = %f", foo.c, foo.a, foo.b);は出力します:

c = 4
a = 1
b = 2.000000

ここで述べたように、これには、指定された初期化子の順序とは無関係に、cthen athenに割り当てるという「驚くべき動作」があります。b

次のような関数がある場合、これは実際の問題になります。

int i = 0;

int f() {
    return ++i;
}

int g() {
    i += 2;
    return i;
}

int h() {
    i += 4;
    return i;
}

そして、私は次のように初期化したいと思いX foo = {.a = (char)f(), .b = g(), .c = h()};ますprintf("c = %d\na = %hhu\nb = %f", foo.c, foo.a, foo.b);:

c = 4
a = 5
b = 7.000000

私の初期化順序が尊重されていないという警告がないという問題がありました。これに対して有効にできる警告または何かがありますか?

実例

4

2 に答える 2

5

C でできる最善の (読み: 妥当な) ことは、構造体を初期化する前に 3 つの一時的な const 変数を宣言することです。それらの宣言順序は、初期化子の評価順序です。

このようなもの:

const char a = f();
const float b = g();
const int c = h();

X foo = {.a = a, .b = b, .c = c};

この場合、関数呼び出しの順序とプログラマーの意図は明らかです。

于 2016-01-05T15:00:19.280 に答える
4

...私の初期化順序が尊重されなかったという警告はありません

特定の初期化順序は、標準に記載されている以外の何かに基づく予想です。(コメントで指摘されているように)

C99セクション 6.7.9、p23: 23 初期化リストの式の評価は、相互に不定に順序付けられるため、副作用が発生する順序は指定されていません。[鉱山を強調]

したがって、未定義 (または未指定) の動作以外は問題ありません。関数の引数の評価順序のあいまいさなど、他の C の動作と非常によく似ています。

EDIT
C99には、それについて次のように書かれています。

C99 から §6.5.2.2p10:
関数の引数の評価の順序が指定されていません , 関数指定子、実引数、および実引数内の部分式の評価の順序は指定されていませんが、実際の呼び出しの前にシーケンス ポイントがあります。
[鉱山を強調]

ここでもっと読む

警告(あなたがよく言った、+1)を好むということは別の問題です。C/C++ 言語で -すべての- -未定義の- -動作-に対して警告を提供することがどれほど実用的かはわかりません。

C++ 標準に Designated Initializers が含まれていない理由について、この議論で述べられているいくつかの仮定/意見に注目することは興味深いことです。(まだ) ...

...C++ は、代わりに型の設計者側に柔軟性を持たせることに関心があるため、設計者は型を正しく使用しやすくし、誤って使用しにくくすることができます。

于 2016-01-05T15:19:25.073 に答える