パック構造体がC言語の一部ではないのはなぜですか?


10

すべてのCコンパイラは、C構造体(__attribute__ ((__packed__))または#pragma pack())を「パック」するオプションを提供します。信頼できる方法でデータを送信または保存する場合は、パッキングが必要であることは誰もが知っています。これは、C言語の最初の日からの要件でもあったに違いありません。

では、なぜパック構造体がC言語仕様の一部ではないのでしょうか。それらの必要性が数十年前から知られているにもかかわらず、それらはC99またはC11にさえありませんか?何が欠けていますか?なぜコンパイラ固有なのですか?


2
純粋なCコードを記述する必要はありません
user253751 14

回答:


7

使用するターゲットCPU /コンパイラの組み合わせに依存するためだと思います。これは、それをどのように指定するかというと、言語の側面よりも、コンパイラディレクティブ(それに関連するもの)の方が優れていることを意味します。彼らがそれを行うことができる唯一の方法は、組合である。

レイモンドの記事は、これがなぜであるかについての洞察を提供しますhttp : //www.catb.org/esr/structure-packing/


非常に興味深い記事。(+1)
ジョルジオ

「12バイトを保持する構造体が必要です。フィールドXはオフセット0で4オクテットのリトルエンディアンとして格納された32ビット整数として動作する必要があります。フィールドYは64ビット整数として動作する必要があります。オクテットバイトのリトルエンディアンとしてオフセット4 "に保存されましたか?どのプラットフォームでもそれを処理するためのコードは、コンパイラーがビットフィールドに対してすでに持っている必要がある種類のものより悪くないはずであり、プログラマーがたまたまネイティブマシンと一致するアラインメントを指定する場合は、はるかに効率的です。他のマシンでは、効率は低下しますが、移植可能です。
スーパーキャット2016年

5

主な要因は3つあります。

  1. 一部のプロセッサは、アラインされていないデータ(たとえば、奇数アドレスから始まる整数または浮動小数点)にアクセスできません。実行しようとすると、例外がトリガーされます。
  2. 一部のプロセッサは、アライメントされていないデータにアクセスできますが、パフォーマンスが低下します。
  3. ほとんどの構造は、C / C ++ソースコードの単一のセットによってアクセスされ、他の言語との相互運用性は例外であり、規則ではありません。

これらの要素を念頭に置いて、標準およびすべてのC / C ++コンパイラーは、構造を定期的にパディングしてプロセッサーの最適なアライメントを確保しますが、相互運用の目的で必要に応じてこれをオーバーライドするメカニズムも提供します。

これは決して見過ごされてきたことではありません。それは非常によく理解されており、現在の状況は設計によるものです。C ++標準の最新バージョンでは、アラインメントの問題を処理するための広範なサポートが提供されていますが、これには慣れていない可能性があります。


パック構造体に対して行われる可能性のあるすべての引数は、ビットフィールドをオプション機能にすることを正当化するためにも使用できます。パックされた構造体のメンバーへのアクセスは一部のプロセッサーでは遅く、他のプロセッサーでは高速ですが、非整列アクセス機能がないためにコンパイラーがユーザーコードの回避策をより効率的なコードに置き換えようとすることは、単にコンパイラーにプログラマーに何を指定させるよりもはるかに複雑です彼らが必要とする。
スーパーキャット2016年

@supercat:あなたは何を主張していますか(または反対ですか)?わかりません。
david.pfx 2016年

ビットフィールドはオプションでなければならないという意見ですが、ビットフィールドが必須の機能になる場合は、構造体のレイアウトを明示的に制御できるように拡張することは理にかなっています。それ以外の場合、最終的な効果として、コンパイラーはレイアウトの完全な制御に必要な作業の90%を実行する必要がありますが、プログラマーは10%のメリットしか得られません。
スーパーキャット2016年

@supercat:ビットフィールドは整数であり、整数と同じビットレイアウトの順序規則に従います。実装が定義されます。構造体のメンバーは、宣言されたとおりに文字の境界で順序付けされます。おそらくパッキングが挿入されます。概念的にはまったく別のものです。[提案を拡大したい場合は、別の質問をする必要がありますが、まったく機能しないと思います。]
david.pfx

0

標準にはないため、コンパイラ固有です。また、アラインメント制限が適用されているあいまいなプラットフォームのコンパイラーに多くの実装作業を必要としない方法で指定することが難しいため、これは標準にはありません。

そして、C89以降のコンパイラを使用する誰もが気にするすべてのコンパイラ/プラットフォームがすでに実装されているので、その努力のどれも正当化の余地はありません。


2
??? あなたは「なぜ標準言語ではないのか」という質問に「標準ではないので」と答えました...
Emilio Garavaglia 14

それは私が最初に考えたものですが、もう一度、「構造体がキーワード「パック」で定義されている場合、そのサイズは各メンバーの追加サイズと同じであることが保証されます。をサポートしないプラットフォーム上で非整列メモリアクセス、構造体メンバー値の1つへのアクセスは未定義の動作です。」これにより、プラットフォーム上の開発者は、少なくとも個々のメンバーの構造体サイズとオフセットを知るために、調整されていないアクセスなしにアクセスできます...
grasbueschel

1
このような構造体をバイトの配列として実装し、各フィールドの値を読み書きするために必要なビットシフトと&/ |操作を実行することにより、ハードウェアでそれをサポートしないシステムで非境界整列アクセスを機能させることが可能です。
dan04 2014

1
@ dan04:多くのプロセッサーでは、コンパイラーは、バイトの読み取りとシフトのシーケンスを使用するよりも効率的な非境界整列アクセス用のコードを生成できます。そのための構文があると、そのようなコンパイラーは、プログラマーがバイトをより長い型にアセンブルするためのコードを記述しようとするさまざまな方法すべてを認識するように要求するよりも効率的なコードを生成しやすくなります。
スーパーキャット2016年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.