コードサンプル:
struct name
{
int a, b;
};
int main()
{
&(((struct name *)NULL)->b);
}
これにより、未定義の動作が発生しますか? 「null を逆参照する」かどうかは議論できますが、C11 では「逆参照」という用語は定義されていません。
6.5.3.2/4 は*
、null ポインターで使用すると未定義の動作が発生することを明確に示しています。ただし、 for と同じことを言っておらず、 beingと->
定義していません。演算子ごとに個別の定義があります。a -> b
(*a).b
->
6.5.2.3/4のセマンティクスは次のように述べています。
-> 演算子と識別子が後に続く後置式は、構造体または共用体オブジェクトのメンバーを指定します。値は、最初の式が指すオブジェクトの名前付きメンバーの値であり、左辺値です。
ただし、NULL
オブジェクトを指していないため、2 番目の文は指定不足のようです。
6.5.3.2/1 も関連する可能性があります。
制約:
単項演算子のオペランドは
&
、関数指定子、 単項演算子[]
または単項演算*
子の結果、またはビット フィールドではなく、レジスタ ストレージ クラス指定子で宣言されていないオブジェクトを指定する左辺値のいずれかでなければなりません。
ただし、太字のテキストには欠陥があり、6.3.2.1/1 ( lvalueの定義) に従って、オブジェクトを指定する可能性のある lvalue を読み取る必要があると思います- C99 は lvalue の定義をめちゃくちゃにしたため、C11 はそれを書き直さなければなりませんでした。セクションが抜けました。
6.3.2.1/1 は言う:
左辺値は、潜在的にオブジェクトを指定する (void 以外のオブジェクト型を持つ) 式です。左辺値が評価時にオブジェクトを指定しない場合、動作は未定義です
ただし、&
演算子はそのオペランドを評価します。(保存された値にはアクセスしませんが、それは異なります)。
この長い一連の推論は、コードが UB を引き起こしていることを示唆しているように見えますが、それはかなり希薄であり、標準の作成者が何を意図したかは私には明らかではありません。実際に彼らが何かを意図していた場合、私たちに議論を任せるのではなく:)