[解決済み] 構造体へのインデックス作成は合法ですか?
質問
コードがどれだけ「悪い」かに関わらず、またアライメントなどがコンパイラやプラットフォームの問題ではないと仮定して、これは未定義または壊れた動作なのでしょうか?
もし私がこのような構造体を持っているとしたら :-)
struct data
{
int a, b, c;
};
struct data thing;
それは
法的
にアクセスすることは
a
,
b
と
c
として
(&thing.a)[0]
,
(&thing.a)[1]
そして
(&thing.a)[2]
?
すべてのケースで、私が試したすべてのコンパイラとプラットフォームで、私が試したすべての設定で、それは「動きました」。私はただ、コンパイラーが b と thing[1] は同じもので、'b'へのストアはレジスタに入れられ、thing[1]はメモリから間違った値を読み取るかもしれません(例えば)。しかし、私が試したすべてのケースでそれは正しいことをしました。(もちろん、それはあまり証明されていないことを認識しています)。
これは私のコードではなく、私が作業しなければならないコードなのですが、これが 悪い コードなのか 壊れた のコードを変更する優先順位に大きな影響を与えるためです :)
タグ付けされたCとC++ 。私は主にC + +に興味があるが、それが異なっている場合は、単に興味のために、Cも。
どのように解決するのですか?
違法です 1 . これはC++のUndefinedな動作です。
メンバーを配列方式で取っていますが、C++の規格では以下のように書かれています(強調)。
[dcl.array/1]のようになります。 : ...arrayタイプのオブジェクトには 連続的に の空でない集合を含む。 サブオブジェクトが含まれます.
しかし、メンバーについては、そのような 連続した の要件はありません。
[class.mem/17]を参照してください。 : ...;実装アライメント要件 は、隣接する2つの メンバが互いにすぐには割り当てられないかもしれません。 ...
上記の2つの引用は、なぜ
struct
へのインデックス付けが C++ 標準で定義された動作でないことを示すのに十分ですが、1 つの例を挙げてみましょう。
(&thing.a)[2]
- 添え字演算子について。
[expr.post//expr.sub/1]です。 : 後置式の後に角括弧で囲まれた式が続くのは 後置表現である。式の一方は "Tの配列 "型のglvalueでなければならない。 「Tの配列 "または "Tへのポインタ "型のprvalueでなければならず,他方はスコープされていない列挙型または は,スコープされていない列挙型又は積分型のprvalueでなければならない。その結果は は,型 "T "である。型 "T "は,完全に定義されたオブジェクト型でなければならない。 式は
E1[E2]
とは(定義上)同一である。((E1)+(E2))
上の引用文の太字部分を掘り下げると、ポインタ型に積分型を追加することについて(ここで強調することに注意してください)...。
[expr.add/4]です。 : 積分型を持つ式がポインタに加算されたり、ポインタから減算されたりすると、結果はポインタのオペランドの型を持ちます。 ポインタに加算または減算されると、結果はポインタオペランドの型になります。 もし が 式
P
は要素を指すx[i]
の 配列 オブジェクトx
をn個の要素で表現するとP + J
とJ + P
(ここでJ
には の値はj
) は(仮説の可能性がある)要素を指す。x[i + j]
もし0 ≤ i + j ≤ n
; さもなければ の場合、動作は未定義です。...
注意点として
配列
の要件に注意してください。
もし
句の要件を満たし、それ以外の場合は
でなければ
を引用しています。という表現は
(&thing.a)[2]
は明らかに
もし
節に該当しません。したがって、未定義の動作です。
余談ですが、私はこのコードとそのバリエーションをさまざまなコンパイラで広範囲に実験しましたが、ここではパディングは導入されませんでした(それは は機能します。 メンテナンスの観点からは、このコードは非常に壊れやすいものです。これを行う前に、実装が連続的にメンバーを割り当てていることを確認する必要があります。そして、インバウンズを維持することです :-)。 でも、まだ未定義のままなんですよね...。
いくつかの実行可能な回避策 (定義された動作を伴う) が他の回答によって提供されています。
コメントで正しく指摘されているように [basic.lval/8]です。 は、前の編集にあったものは適用されません。2501さん、@M.M.さんありがとうございます。
1
: この質問に対する @Barry の回答で、唯一合法的にアクセスできるケースを紹介しています。
thing.a
メンバにアクセスできる唯一の合法的なケースについては、@Barry の回答を参照してください。
関連
-
[解決済み] テスト
-
[解決済み】非静的メンバ関数への参照を呼び出す必要がある
-
[解決済み】浮動小数点数の乱数生成
-
[解決済み] C++でクラスと構造体はいつ使い分けるべきか?
-
[解決済み] C++の'struct'と'typedef struct'の違い?
-
[解決済み] .NETにおけるstructとclassの違いは何ですか?
-
[解決済み] 構造体のsizeofは、なぜ各メンバーのsizeofの合計と等しくないのですか?
-
[解決済み] C言語標準に準拠した構造体の初期化方法
-
[解決済み] Intel CPU の _mm_popcnt_u64 で、32 ビットのループカウンターを 64 ビットに置き換えると、パフォーマンスが著しく低下します。
-
[解決済み] C 言語の単一構造体メンバのサイズ
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】 unsigned int vs. size_t
-
[解決済み】C++ 非推奨の文字列定数から「char*」への変換について
-
[解決済み】識別子 "string "は未定義?
-
[解決済み】 != と =! の違いと例(C++の場合)
-
[解決済み] string does not name a type Errorが発生するのはなぜですか?
-
[解決済み】変数 '' を抽象型 '' と宣言できない。
-
[解決済み】c++でstd::vectorを返すための効率的な方法
-
[解決済み] 非静的データメンバの無効な使用
-
[解決済み】エラー:不完全な型へのメンバーアクセス:前方宣言の
-
[解決済み】C++ - 適切なデフォルトコンストラクタがない [重複]。