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

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

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

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

Q&A

5回答

4870閲覧

C アライメントに関して

sample__

総合スコア0

C

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

0グッド

2クリップ

投稿2020/07/29 09:19

編集2022/01/12 10:55

そもそもC言語のアライメントに関して本当に理解してやっている人はいるんですか?

理屈の話ではなく一般的にはx86CPUなら4バイト境界にアラインさせるのが一番効率がよいと言われています。
x86はメモリアクセスに寛容だから無理にアラインさせなくても一応アクセスは可能。
(逆に言うならばメモリの節約が可能)

メモリを節約しなければいけない状況
アクセス効率を重視する状況

などそれぞれの要件によってどのようにアライメントを揃えるかというのは変わってくると思います。

では、たまに見る

「2バイト整数は2の倍数のアドレスに配置・アラインさせる」

という記述は何ですか?

これは何を目的としたアラインのさせかたなんですか?

(まぁ、本当にアクセス効率を重視したいなら個々のアライメントというよりある程度の大きさのデータ配置を気にしたほうがいいのかな?)

リンク内容
イメージ説明
CPU とデータ型によって異なるが
⇒これはわかる。

⇒つまり1バイト整数のアラインメントは1バイト, 2バイト整数のアラインメントは2バイト, 4バイト整数/単精度浮動小数のアラインメントは4バイト, 8バイト倍精度浮動小数のアラインメントは8バイトである.

一般って何?

理解力が低い私にはとてもじゃないけど理解できない記事でした。

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

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

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

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

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

episteme

2020/07/29 10:45

「C言語のアライメント」って何ですか?
Q71

2020/07/29 11:10

C#とPythonで画像データの交換をしていますが、アライメントを整えないと画像が乱れます。物理メモリへのアクセスに限ったことでもありません。
episteme

2020/07/29 12:21

↑それは画像のピクセル幅を4nにしろとか、そーゆーやつのことですか?
sample__

2020/07/29 12:51

>「C言語のアライメント」って何ですか? 用語が適切ではありませんでした。 ふつうに"アライメント"です。 >Q71 今回のはメモリのほう限定で・・・
raccy

2020/07/29 13:18

「2バイト整数は2の倍数のアドレスに配置・アラインさせる」 という記述をよく見ると言いますが、検索してもでてきませんでした。aligneさせた目的が何だったのかは前後の文脈がわからないと正確なことは言えないのではないかと思います。あなたが記述を見たという書籍なりサイトなりを明記して貰えますか?
sample__

2020/07/29 13:26 編集

確かにそうですね。 今探します 見つけたらリンク載せます
sample__

2020/07/29 13:30

追記しました。
raccy

2020/07/29 13:46

そのサイトは更新はされているようですが、C11以降にある_Alignofや_Alignasに対する記述がないので調査の仕方や調整の仕方が中途半端な気がします。こんな質問をするのですから、C11の_Alignofや_Alignasはもちろん知っていますよね?
sample__

2020/07/29 13:52

わかりません C11って何ですか? そのサイトに記述されているのでしょうか?(C11で検索をかけても出てこなかった) ぐぐっても機関車のC11しか出てきませんでした。 教えていただけると助かります。
sample__

2020/07/29 14:03

助かります。
ikadzuchi

2020/07/29 14:17

> 一般的にはx86CPUなら4バイト境界にアラインさせるのが一番効率がよいと言われています。 文脈からして、1バイトや2バイトの整数を1バイトや2バイトでアラインさせるより4バイトでアラインさせた方が読み書きが高速ということですね。 そのようなことは寡聞にして知りませんが、きちんとしたソースはありますか? > 一般って何? 文中に「一般」という言葉はありませんが、どこを指しているのでしょう。 > x86? CPUによって異なると言っているのに、なぜ1つのCPUだけを示すのですか?
sample__

2020/07/29 14:24

何バイト境界にアラインすればよいか (これをアラインメント注4 (alignment) という) は,CPU とデータ型によって異なるが,一般には2の冪乗 (1,2,4,8,16,…) になる. ここですね。解釈によって変わる気がする >そのようなことは寡聞にして知りませんが、きちんとしたソースはありますか? そういえばキチンとしたソースというのはない。 逆に僕はキチンとしたソース(日本語)を見つけられていません。 キチンとしたものを見つけられていたら アライメントのことでこんなに足踏みし続けることはなかった。 >CPUによって異なると言っているのに、なぜ1つのCPUだけを示すのですか? 確かにそうですね。消します
maisumakun

2020/07/29 14:26

結局の所、「何が知りたい」のかがうまく伝わってこない印象です。 (具体的に困っていることがあるなら、それを明示してもらえると助かります)
sample__

2020/07/29 14:37

何を分からないかをどう伝えるかがわからないというべきか・・・(?) ちょっと考えます・・・
ikadzuchi

2020/07/29 14:44

> 何バイト境界に~になる. > ここですね。 一般はどこを指すかに対する返答でしょうか。 一般に2の冪乗になることは疑問の余地はありませんね? あなたが疑問視しているのはnバイト整数のアラインメントがnバイトになるべきか否かですよね? どうも文章をきちんと読んでいるか疑問です。 > そういえばキチンとしたソースというのはない。 > 逆に僕はキチンとしたソース(日本語)を見つけられていません。 何語でも構いませんが、質問の前提となっている物事がソース無しとなると、まずは前提を疑うのが先ではないかなあという気がしますね。 1,2バイト整数を4バイトアラインで速くなる要因が私には思いつきません。
sample__

2020/07/31 14:52

今回のx86において4バイトアライメントが一番効率が良いといったことを撤回します。 アライメント関連の記事には4バイト境界にアラインさせるというのがよく書かれていますが 私がそれを勝手にメモリアクセスの効率がよいものなんだと思い込んだだけのようです。 ごめんなさい。
FKD

2020/08/03 05:27 編集

蛇足かもしれませんが、x86系はPentiumあたりからデータバス幅が64bitだったりするので、現在はアライメントは8バイトが効率よいです。 また、このあたりの話は、メインメモリとCPUキャッシュの速度差も考慮しないと腑に落ちないかもしれません。(メインメモリは遅いので、アクセス回数が最小になるようにアライメントをそろえる) 以下を参照してみてください。(GIGAZINEの記事) https://gigazine.net/news/20180911-access-speed-history/
guest

回答5

0

C言語のアライメントに関して本当に理解してやっている人はいるんですか?

理解してる人はたくさんいると思いますよ。

理解力が低い私にはとてもじゃないけど理解できない記事でした

そう言われれば、プログラマが理解していなくてもそれほど困らない事かもしれませんね。なぜならアラインするのはCコンパイラですから。プログラマが知らない間にコンパイラは全ての変数を適切にアラインしてくれています。あなたがアラインメントを知らないばかりにプログラムが動かなかった、なんてことはなかったはずです。まずはご安心を。

でも時々、コンパイラがどうアラインするか、意識することがあります。それは構造体を使う時です。次のコードをコンパイルして動かしてみてください。

C

1#include <stdio.h> 2#include <stdint.h> 3//#pragma pack(4) // <= 試せるなら 4 5struct A { 6 double d; // 8 7 float f; // 4 8 int32_t a; // 4 9 int16_t b; // 2 10 int16_t c; // 2 11}; 12struct B { 13 int32_t a; 14 double d; 15 int16_t b; 16 float f; 17 int16_t c; 18}; 19 20int main(void) 21{ 22 printf("A: %ld bytes.\n", sizeof(struct A)); 23 printf("B: %ld bytes.\n", sizeof(struct B)); 24 return 0; 25}

struct A と struct B はどちらも同じメンバ変数を持っていますが、並べた順序が違います。私の手元で実行すると、結果はこうでした。

bash

1# ./a.exe 2A: 24 bytes. 3B: 32 bytes.

もしアラインメントが一切無いなら両方同じバイト数になりますが、そうはならない。メンバ変数の並びが違うので、それぞれのメンバをアラインした結果、 struct B には struct A よりも隙間が多くなったのです。
質問者もお手元で確かめてください。

私の場合、違いは8バイトです。構造体一個のサイズが8バイト違っても大勢に影響は無いでしょう。なにせ今時のパソコンはGBオーダーのメモリを積んでますから。
でも構造体を配列にしたら、その差は拡大します。例えば要素数1000の配列なら、違いは8000バイトです。それだけメモリが無駄になってしまいます。組込みの世界では今だってメモリサイズの制約が大きいので、こうしたことに敏感です。

構造体のメンバ変数は、プログラマが書いた通りに配置されます(Cコンパイラはメンバ変数の順序を変えない)ので、ここの順序はプログラマの責任です。気にするのは当然でしょう。

「2バイト整数は2の倍数のアドレスに配置・アラインさせる」という記述は何ですか?

上のコードには int16_t 型のメンバ変数 b, c を含めました。b, c は2の倍数アドレスにアラインされるので二つ続けて並べれば、隙間なく配置できる=隙間を減らせるというわけです。

念のため繰り返しますが、アラインメントを理解できなくてもCプログラムを動かすことに大きな支障はないと思いますし、気にしなくて済む分野のソフトウェアはいくらでもあります。

投稿2020/07/30 03:12

rubato6809

総合スコア1380

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

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

sample__

2020/07/31 14:53

コンパイラの設計次第ですね。 >困らない事かもしれませんね。 仕事ではなく趣味としてやっている身としてはどうしても 細かい部分も気になるものです。
rubato6809

2020/08/03 10:44

気になる点、未解決な事があるんですよね? そこを明確にすれば誰かが答えると思いますが。
guest

0

「2バイト整数は2の倍数のアドレスに配置・アラインさせる」

メモリアクセスの効率を良くする(というよりは悪くしない)ではないですか?
16bitとか32bitのデータバス幅でアクセスしているなら、奇数アドレスに始まる16bitデータは物理メモリにアクセスが2回必要になる可能性があります。偶数アドレスで始まっていれば確実に1回でアクセスできます。

(余談)8088はこの仕様で"やっぱり8bitマイコン"だなぁ、と思わせたものでした。

投稿2020/07/29 13:40

thkana

総合スコア7610

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

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

sample__

2020/07/29 13:48

8bitCPUってアライメント関係ないような気がするのですが・・・ 言い方を変えます。 ※x86では4バイト境界にアラインさせるのが最もアクセス効率がよいとする。 なぜ、もっともアクセス効率が良いはずの4byte境界にアラインではなく 「2バイト整数は2の倍数のアドレスに配置・アラインさせる」 なんていう方法をとっているのかがとても気になります。 4バイトの倍数から始まるアドレスからデータが配置されていないなら少なからずアクセス効率は下がると思います。
sample__

2020/07/29 13:58

(ちょっと関係ないけど)知恵袋とかで情報収集していて断片的に知識を吸収していて ごちゃごちゃになってる部分もあるけど 人(知恵袋の回答者)によってアライメントの認識が違うようです。 どれが正しい情報なのかということを 調べても分からない私が判断できるわけないわけですが。。。
thkana

2020/07/29 14:03

8088つまり8086はアライメント関係なく(奇数バイトからワードデータが始まっても)アクセス出来るように作られてるから(インテルが16bitと言っているにもかかわらず)8bitCPUのニオイがするよね、というだけの話です。余計なことを言って混乱させてしまいましたか。 > なぜ、もっともアクセス効率が良いはずの4byte境界にアラインではなく 設計思想でしょう。私が設計したわけではないので想像するばかりですが、16bit時代のプログラムをそのままのデータ幅でコンパイルしたのにメモリ消費がド~ンと大きくなったりするのを嫌がったんじゃないですか。 もう一つ、実際にどうなっているかは知りませんが、内部回路で上位ワードと下位ワードを入れ替えるなんてのは簡単なことですから、2byteデータを4byteでアラインメントしなくてもそんなにアクセスコストは掛からないようにできる(2byteアライメントで十分)、という可能性もあります。
sample__

2020/07/29 14:06

その発想は思いつきませんでした。 ありがとうございます
maisumakun

2020/07/29 14:15 編集

> 4バイトの倍数から始まるアドレスからデータが配置されていないなら少なからずアクセス効率は下がると思います。 2バイト整数を4バイトアラインで詰めれば、当然半分しかメモリは使われないのでメモリ効率は落ちます。C言語は演算のたびに「標準変換」でint未満がintに格上げされてしまうというように、基本の型がintベースとなっていますので、「速度」を考えるならそもそもshortは選択肢になりません。
maisumakun

2020/07/29 14:17

また、規格上sizeof(char)は1でなければならず、また配列は型ごとのサイズに合わせて並ぶものなので、charのアライメントは(規格に則った処理系であれば)必ず1です。
FKD

2020/07/30 03:53

>4バイトの倍数から始まるアドレスからデータが配置されていないなら少なからずアクセス効率は下がると思います。 データバス幅32bitであれば、32bit単位でメモリから読み込むので、 16bit要素が連続(配列等)していれば、一回で2要素読める可能性があります。(CPUキャッシュに乗ります) 逆に、アクセス効率が下がるケースってなにかありますか?
ikadzuchi

2020/07/30 16:47

> 「速度」を考えるならそもそもshortは選択肢になりません。 あまりそうは思えなかったので試してみましたが、どうやら同じかshortがわずかに速いですね。 コメント欄に長いコードを書くのは憚られるので言葉で説明すると、「「1000要素用意して順に加算」を100万回」をintとshortと1つ飛ばしのshortで、x64マシン上のgccで試しました。
pepperleaf

2020/08/01 04:59

8088が 8bit CPUの匂いがするするってのはまあ、時代背景でしょう。ソフトウェアより、ハードウェアの都合で、周辺機器(チップ)が 8bit CPUのものが流用できるので、安く上がるって事だったと思います。(で、16bitと威張れる) 多分、時代を考えないと意味不明。
guest

0

maisumakun 2020/07/29 19:24
x86でも、SSEを扱う場合には「16バイト境界にアラインする必要がある」ような場面も出現します。

コメントで埋もれてしまうにはあまりにももったいないので、SSEじゃなくてAVX2ですが、その事例をteratailの回答で書いたことがあったので、紹介しておきます。

https://teratail.com/questions/140753#reply-213221

ソースコードは上記回答にあるリンク先のgistを見てください。

AVX2命令は256ビットを一度に扱うもので、アライメントのサイズは32バイトです。アライメント調整のために動的にメモリ確保しているところはaligned_allocを使っているのがわかると思います。

そもそもC言語のアライメントに関して本当に理解してやっている人はいるんですか?

理解していない人には、SSE等を扱うのは無理でしょう。ただ、CPUによって分岐を書く必要があったりするし、高パフォーマンスが必要になるライブラリ(例えばlibwebp等)以外は使っている人は少ないと思います。

投稿2020/07/31 15:41

raccy

総合スコア21733

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

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

0

アライメントは、CPUのバス幅やアーキテクチャにより変わるもんです

#組み込み向けなどのメモリが制限されてる環境なんかでは、アライメント意識しないと、まともに動かすことはできませんな。

投稿2020/07/29 09:25

y_waiwai

総合スコア87719

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

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

sample__

2020/07/29 09:28

組み込みのCPUなんかだと速度が遅いからでしたっけ・・・(?) まぁ、その話は分からないけど x86のアライメントの記事なんかを読んでいると 「2バイト整数は2の倍数のアドレスに配置・アラインさせる」 みたいのをよく見るんですよ。 しかもそういう記事らってのは上記のものと CPUのワードサイズにアラインさせる説明を一緒に書いてるものだから よくわからなくなってきます・・・(?) 結局どっち?何を重点においた場合のアラインなの?という感じ。
sample__

2020/07/29 09:29

CPUのワードサイズにアラインさせなきゃいけない設計のCPUなら一択なんですけどね・・・
y_waiwai

2020/07/29 09:38

パソコンのCPUであれば、(X86とかX64とか)アライメントの外れた変数の定義しても、それに応じてアクセス法を変えて読み込んでくれます(が速度が遅くなる)んでいいんですが、 ARMなどのCPUでは、アライメントをきちんとしないと例外が出ます まあ、CPUによりそこらへんの事情は変わってくるんで、統一した説明は難しいかと思います
maisumakun

2020/07/29 10:24

x86でも、SSEを扱う場合には「16バイト境界にアラインする必要がある」ような場面も出現します。
sample__

2020/07/29 13:02

あ、wikiでもx86に関して "ただし、アライメントを整える必要がある場合がある" って書かれてたような・・・ まぁ、そこまでアライメントに気をつかう場面があるかって言われたらないのかな(?) ちょっと前に知恵袋でも同じような質問した気がするが 適格(?)に答えてくれた人はいなかったような・・・ やっぱそこまで理解している人は少ないのかな (果たしてそれを理解している人がこのサイトを利用していて僕の質問を見てくれているかさえわからないが・・・)
退会済みユーザー

退会済みユーザー

2020/07/29 14:21

最近流行りの殆どメモリ意識する必要ない言語しか触らない開発者だと、アライメントとか知らないって人は多いんじゃないですかね。(逆に言えば知る必要がないとも言う) そこまで意識したのは、数年前にアセンブラで画像処理用のライブラリ書いた時くらいかな…
sample__

2020/07/29 14:25

やっぱそうなるんですかね。
guest

0

まだ、閉じてないみたいなので、、

今、C言語とか、その他の高級言語でプログラムを書く時には、意識する必要のないものだと思います。VCだと、アライメントに合わせてメモリ割付けしてくれるし、特殊なパラメータ設定、または裏技でないと、不正な配置に置くことができないと考えています。

アライメントを考えるのは、少しでもメモリ効率を良くしようとか、少しでも速くなんて考える、または、組み込み系の非力なチップを使う時くらいではないでしょうか。そして、最近のPCで使われているチップ(Intel, ARM,...)では、キャッシュとか色々とあって、下手な(手作業の)最適化は、却って効率を落とすだけでしょう。

昔(20世紀)だと色々とありました。32bit CPUで、4byte整数を4byte境界に、合わせないとバスエラー例外とか、下位 2bitを無視してアクセスするCPUとか。byteアドレスと wordアドレスが違うものとか。(byte → word は、1bit シフト)

そういう意味では、(一般のアプリでは)アライメントを意識しなくても良い時代になったと思っています。

投稿2020/08/01 05:19

pepperleaf

総合スコア6383

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問