質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

ファイル

ファイルとは、文字列に基づいた名前又はパスからアクセスすることができる、任意の情報のブロック又は情報を格納するためのリソースです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

API

APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

Q&A

解決済

4回答

5943閲覧

構造体変数のファイル出力におけるパディングの問題

JADEN

総合スコア106

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

ファイル

ファイルとは、文字列に基づいた名前又はパスからアクセスすることができる、任意の情報のブロック又は情報を格納するためのリソースです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

API

APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

0グッド

2クリップ

投稿2016/02/22 13:09

編集2016/02/22 13:13

パディングを無視して、構造体変数自体を保存できる理由が分かりません。

以下のサイトで、可変長配列メンバを利用した、構造体変数自体のファイル出力を行っています。
ただ、パディングが行われる可能性があるため、構造体変数自体のファイル出力は好ましくないと思います。
参照サイト: ロベールのC++教室 - 第15章 伸縮自在 -

なぜなら、あるCPUを使用した環境において、パディングが行われない様にメンバ変数のサイズを決めたとしても、アライメントはCPUに起因するため、CPUが異なる場合に、パディングが行われない保証はないと思うからです。

ただ、上記のサイトにも書かれているのですが、Windows APIのBITMAPINFO構造体も、可変長配列メンバを利用し、構造体変数自体をファイル出力する仕様になっています。
参照サイト: BITMAPINFO構造体 -MSDN-

Windows APIが利用している以上、CPUに依存せずパディングを回避して、構造体変数自体をファイル出力できる仕組みがあると思うのですが、それが何か教えてもらえないでしょうか。

最後に、関連した質問で、可変長配列メンバの利用理由として、
・メモリの節約
・ファイル出力関数の呼び出し回数の抑制
以外に何かあれば教えてください。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

ベストアンサー

パディングが行われる可能性があるため、構造体変数自体のファイル出力は好ましくないと思います。

場合にもよります。パディングは変数のサイズに応じて決まるので、「パディングを作らない」ようにすれば、問題は起こりません。

Windows APIが利用している以上、CPUに依存せずパディングを回避して

BITMAPINFO(BITMAPINFOHEADER)構造体の中身を見れば判りますが、パディングはありません
元々Windows(NT系)はマルチプラットフォーム向けに開発されているので、パディングを取ってアラインメントをまたがるように配置してしまうと、CPUによってはアクセスできなくなる可能性があるため、Windows APIでは、時にはダミーの変数を挟んだりしてパディングが発生しないように構造体を設計しています。


追記
すでに決められたファイル構造(フォーマット)で読み書きする場合は、パッキングする必要がありますね。

投稿2016/02/22 14:08

編集2016/02/23 03:50
catsforepaw

総合スコア5938

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

JADEN

2016/02/23 11:15 編集

回答ありがとうございます。 >>BITMAPINFO(BITMAPINFOHEADER)構造体の中身を見れば判りますが、パディングはありません。 Chironianさんが書かれている様に、Windowsはx86が主な対象で、アライメントが全て予測できるから、という理解で良いですか? と思ったのですが、 >>パディングを取ってアラインメントをまたがるように配置してしまうと、CPUによってはアクセスできなくなる可能性がある マルチプラットフォーム向けであるため、CPUが変わり不正アライメントエラーが起き得るということは、アライメントがx86系と異なる変なCPUだったらという可能性は考えなくて良いのでしょうか(パディングが入る可能性があるのでは?)。
catsforepaw

2016/02/23 15:08

> Windowsはx86が主な対象で、アライメントが全て予測できるから、という理解で良いですか? ちょっと違います。アラインメントはCPUで決まるのではなく、変数のサイズで決まります。shortは2バイト、intは4バイト、doubleは8バイトという具合です。それぞれのメンバ変数をそのアラインメントに合わせて配置すれば、パディングは発生しません。 > アライメントがx86系と異なる変なCPUだったらという可能性は考えなくて良いのでしょうか(パディングが入る可能性があるのでは?)。 前述のようにアラインメントはCPUではなく変数で決まります。CPUが変わったからパディングが入るというものではありません。
catsforepaw

2016/02/23 16:46

> サイトが正しい保証はありませんが、1. cpuに関する基礎知識に書いてあります。 「アラインメント」の使われ方の違いですね。確かに混乱するかもしれません。 CPUのメモリアクセスなどの文脈でアラインメントを使う場合は、バス幅によって決まるバイト境界のことを指すかもしれません。 私はご質問の文脈から「パディングが入るかどうか」の観点でのデータ整列の意味のアラインメントと解釈してそのように使いました。
JADEN

2016/02/24 11:30 編集

混乱してきました。 BITMAPINFOHEADER構造体は、WORD(16bit), DWORD(32bit), LONG(32bit)で構成されているため、32bit(16bit) CPUだと4(2)バイトアライメントなので、BITMAPINFO構造体のパディングがないことは分かります(RGBQUAD構造体は4つのメンバがBYTE(8bit)なので)。 しかし、仮に24bit CPU(このCPUが実現できるかどうか知りません)である場合、(1バイトが8ビットだとすると)3バイトアライメントになるため、WORD、DWORD、LONGの全てにパディングが入ってしまうのではないでしょうか? (WORD: 2+1=3byte, DWORD(LONG): 4+2=6byte)
catsforepaw

2016/02/24 12:04

存在しないものをあれこれ考えるのは、混乱を深めるだけだと思うのですが……。 確かに24bit CPUならアラインメントは3バイト境界になるでしょうけど、同時にそのCPU専用のコンパイラーではWORDは3バイト、DWORDは6バイトと定義されるでしょうから、やはりパディングは発生しないでしょう。
YsMana

2016/02/24 12:07

そういう検討は、Windowsが新しいCPUをサポートするときにWindowsの開発者がするでしょう。 そのときに必要なら、新しいCPUのために構造体の定義にコンパイラディレクティブを追加したりするんじゃないでしょうか。 今は、今のWindowsがサポートしているプラットフォームに限定して動作すれば良いわけですし。
Chironian

2016/02/24 14:03 編集

JADENさん。 変数のアライメントはCPUがその変数をアクセスするため、もしくは、高速にアクセスするための調整ですので、CPUに起因することで間違いないです。 catsforepawさんが言われている話は、CPUを問わずバディングを入れないようにするための方法と思います。JADENさんの質問はそれを聞いているように読み取れます。 私は、JDENさんのCPUを問わずパディングを回避する目的を、「構造体を保存したファイルのCPU間の互換性を取ること」と理解して回答しました。そもそもエンディアン問題があるので構造体のCPU間互換性を維持する方法は存在しませんと。 JADENさんはパディングが入るとどんな好ましくないことが発生するとお考えですか? 具体例を少し挙げて頂けると良いと思います。
JADEN

2016/02/25 11:38 編集

>>存在しないものをあれこれ考えるのは、混乱を深めるだけだと思うのですが……。 むしろ、この問題が聞きたいことだったので、私の質問の仕方が良くありませんでした。 あらゆる可能性を考慮して、柔軟性を持たせなければならないのではと思い質問しました。 CPUに合わせてコンパイラが設計されるため、変数サイズでアライメントを考えれば問題ないということですね。 >>具体例を少し挙げて頂けると良いと思います。 あるPCでbitmapを保存します(パディングされた状態で保存)。 そのファイルを別のPCに移動し、ファイルを読み込みます。 そのPCのアライメントではbitmap構造体にパディングが生じない場合、構造体のサイズとファイルに保存されているデータサイズが異なるため、読み込みデータが不正になります。 この逆もあり得ます。 と思っていました。
catsforepaw

2016/02/25 12:31

JADEN さん > CPUに合わせてコンパイラが設計されるため、変数サイズでアライメントを考えれば問題ないということですね。 そうです。それが言いたかったのです。言葉足らずですみません。
Chironian

2016/02/25 13:17

JADENさん。 やはりCPU間の互換性を気にされていたのですね。 結論としては、任意のCPU間で構造体のままデータをやり取りすることは不可能です。 例えば、2バイトの符号付き整数を表現する型にint16_tがあります。これをメモリに保存する際に、Low-Byte→High-Byteの順序で保存するCPUと、その逆順で保存するCPUの両方があります。どちらもそこそこメジャーです。前者をリトル・エンディアン、後者をビック・エンディアンといいます。 例えば、0x1234を保存する時、前者は34 12と保存し、後者は12 34と保存します。 もし、前者が保存したファイルを後者が読むと、0x1234ではなく0x3412と読み出せてしまいます。この問題をCPUを問わずに解決できる術は存在しません。 もしも、24ビットCPUがあったとして、そのCPUでのint16_tのアライメントは3バイトになるでしょう。int16_tを2つ並べると仰るようにパディングが入ります。 そのCPUがアライメント境界にまたがるデータを取り扱えないタイプのCPUでしたら、この構造体をパックしてしまうと2つ目のint16_tをint16_tデータとして扱えなくなります。 しかし、アライメントを付けると、16ビットCPUで取り扱えなくなります。 NECのACOS-6というコンピュータは1ワード36ビット、1バイト9ビットだそうです。構造体のまま互換を取るなんて夢物語と思いません? CPU間でデータ互換性を確保する必要がある場合、構造体のままだとエンディアン、アライメント、データサイズ等の変換に苦労するので、htmlのようにテキスト形式が使われることも少なくないようです。
JADEN

2016/02/27 05:02 編集

>>そのCPUがアライメント境界にまたがるデータを取り扱えないタイプのCPUでしたら、この構造体をパックしてしまうと2つ目のint16_tをint16_tデータとして扱えなくなります。 パックとは、パディングせず詰めるということで合っていますか?
Chironian

2016/02/27 05:16

はい。その通りです。
JADEN

2016/02/27 06:27

皆さん、回答ありがとうございました。 非常に勉強になりました。 また、宜しくお願い致します。
guest

0

パディングについて・・・記憶違いがあるかもしれませんが、パディングについてはCPUやOSの違いではなく(元々はCPUアーキテクチャの問題ですが)コンパイラの仕様に強くかかわっています。過去、86系あるいは68系(他にもある)はメモリアクセスがかなり制限されていました(奇数番地から多バイトの読み出しは不可、もしくは時間が掛かったなど)、その為にパディングが必要でした。その為に、コンパイラもそのようになったのだと思います。 参考:http://itpro.nikkeibp.co.jp/article/COLUMN/20070509/270418/?rt=nocnt

投稿2016/02/23 15:58

編集2016/02/23 16:10
cateye

総合スコア6851

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

こんにちは。

ただ、パディングが行われる可能性があるため、構造体変数自体のファイル出力は好ましくないと思います。

リンク先でも触れられているように手間と移植性を天秤にかけることになります。
例えば、そのプログラムが特定のCPUでしか動く必要がないのであれば常に同じパディングになるはずですから手間を省いてもなんら問題ないと思います。

移植性を考慮する場合はそうもいきませんが、その時はエンディアンの相違が最も頭痛いです。エンディアンが異なるCPU間では構造体をそのまま保存するなんて出来ません。ファイル上のエンディアンを定め、それと異なるCPUの場合はエンディアン変換が必要になります。それを同一ソースから生成するって正直悪夢かも。(だから、xmlやJson等がこんなに広まったのではないかと思ってます。)
それに比べるとアライメント合わせは児戯に等しいです。対象CPUが決まっているのなら、ちょっと注意深く構造体を定義すれば良いのですから。

Windows APIが利用している以上、CPUに依存せずパディングを回避して、構造体変数自体をファイル出力できる仕組みがあると思う

Windowsって基本的には80x86(歳が分かりますね)が主な対象CPUですね。インテルは上位互換を維持しつつ、新しいCPUを開発しているのでアライメントも互換が取れていると思います。
ARMなどでも動くWindowsはあるようですが、ファイルの互換性はレアなWindows側で頑張って維持している、もしくは、そもそも諦めているのではないかと思います。

最後に、関連した質問で、可変長配列メンバの利用理由として、

・メモリの節約
・ファイル出力関数の呼び出し回数の抑制
以外に何かあれば教えてください。

複数の断片的なメモリで管理するより、1つの連続したメモリで管理できた方がプログラムがそれなりに簡単になると思います。

投稿2016/02/22 14:05

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

catsforepaw

2016/02/22 14:25

> Windowsって基本的には80x86(歳が分かりますね)が主な対象CPUですね。 過去にはMIPS、Alpha、PowerPCにも対応していましたよ(歳がばれる?)。
Chironian

2016/02/23 00:40

それは全面的に作りなおされたWindows NTからですよ。(歳、勝ったかな?) それ以前のWindows 3.1とか95などはMS-DOS上で走ってました。MS-DOSをマルチプラットフォームにするって発想はたぶんなかっただろうと思います。 その頃もBITMAPINFO構造体はあります。しかも、ビットマップ・ファイルで一緒に使われるBITMAPFILEHEADERとか、2バイトアラインですし。
catsforepaw

2016/02/23 03:42

BITMAPFILEHEADERのことをすっかり忘れていました。一応ヘッダーの中も見たのですが`#pragma pack`がなかったので見落としていました。ファイルフォーマットがらみではpackしている構造体もありますね。
guest

0

https://msdn.microsoft.com/ja-jp/library/ms253935(v=vs.90).aspx
#pragma pack ディレクティブがそうです。

投稿2016/02/22 13:35

編集2016/02/22 23:58
yuba

総合スコア5568

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問