ドラフト C99 標準セクションから、初期化リスト式の評価の順序が指定されていないため、ここでは指定されていない動作の対象になっているようです6.7.8
。
初期化リストの式の中で副作用が発生する順序は規定されていません。133)
ノート 133 は次のように述べています。
特に、評価順序は、サブオブジェクトの初期化の順序と同じである必要はありません。
私が知る限り、メモをバックアップする規範的なテキスト133
はセクションからのもの6.5
です:
後で指定する場合を除き [...] 部分式の評価の順序と副作用が発生する順序はどちらも指定されていません。
そして、初期化子が完全な式であることがわかります6.8
(強調鉱山):
完全な式は、別の式または宣言子の一部ではない式です。
次のそれぞれは完全な式です。[...]
初期化子内のシーケンスポイントをカバーし、完全な式を別の場所に配置する私の古いC++の回答の1つを振り返った後、最初に結論付けた後、含まれている初期化子の文法に2回気づきました。6.7.8
initializer:
assignment-expression
{ initializer-list }
{ initializer-list , }
initializer-list:
designationopt initializer
initializer-list , designationopt initializer
私はもともとこれに気づいておらず、上記の文法のトップ要素に適用される完全表現に関するステートメントを考えていました。
C++ のように、完全な式が初期化子リスト内の各初期化子に適用されるため、以前の分析が正しくないと考えています。
欠陥レポート 439は、これが事実であるという私の疑いを裏付けるもので、次の例が含まれています。
#include <stdio.h>
#define ONE_INIT '0' + i++ % 3
#define INITIALIZERS [2] = ONE_INIT, [1] = ONE_INIT, [0] = ONE_INIT
int main()
{
int i = 0;
char x[4] = { INITIALIZERS }; // case 1
puts(x);
puts((char [4]){ INITIALIZERS }); // case 2
puts((char [4]){ INITIALIZERS } + i % 2); // case 3
}
そしてそれは言います:
INITIALIZERS マクロを使用するたびに、変数 i が 3 回インクリメントされます。ケース 1 と 2 の場合、未定義の動作はありません。これは、インクリメントが、順序付けされていないのではなく、互いに不定に順序付けられた式にあるためです。
したがって、内部の各初期化子INITIALIZERS
は完全な式です。
この欠陥レポートは C11 に対するものであるため、この問題に関する規範的なテキストでは、C11 は C99 よりも詳細であり、次のように記載されていることに注意してください。
初期化リストの式の評価は、相互に不定な順序で行われるため、副作用が発生する順序は指定されていません。152)
values
の各要素が割り当てられる前に次の式が評価される場合、未定義の動作があります。
values[0] + values[5]
また:
values[5]/10
不確定な値を使用すると未定義の動作が呼び出されるため、これは未定義の動作です。
この特定のケースでは、最も簡単な回避策は、手動で計算を実行することです。
int values[10] = {
[0]=197,[2]=-100,[5]=350,
[3]= 197 + 350,
[9]= 350/10
};
3
要素への割り当てや初期化の後に行うなど、他の選択肢があり9
ます。