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

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

ただいまの
回答率

90.33%

  • C

    3992questions

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

  • C++

    3768questions

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

  • CPU

    40questions

変数の型とCPUの関係

解決済

回答 5

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 553

strike1217

score 563

変数の型とCPUの関係についてです。
何度か質問しているのですが・・・どうも理解できません。
頭が痛いです。

int型を例に取りましょう。
自分の環境では、int型4バイトです。
8bit = 1byteとします。

int型のサイズは処理系依存と言われます。しかし、この処理系依存という言葉・・・具体的に何を指しているんだろう?という疑問があります。
CPUやOS,コンパイラ・・・etc.

「組み込み現場のC言語」という本には

int型のサイズはビット長はレジスタ長に依存する

とあります。つまりCPUですね。

[C++] intのサイズはコンパイラやプロセッサに依存しますか? 

16ビットマシンでは、sizeof(int)は2バイトでした。 32ビットマシンはint場合4バイトです。 intサイズはプロセッサのネイティブサイズ、つまりレジスタのサイズであると考えられています。 しかし、32ビットコンピュータは非常に人気があり、32ビットプログラミングモデル用に膨大な数のソフトウェアが作成されています。 したがって、64ビットコンピュータがintために8バイトを持つなら、それは非常に混乱します。 LinuxとWindowsはともにint 4バイトのままです。

え?
つまり、現在はint型はCPUに依存したサイズではない・・・ということですよね?
「昔はint型のサイズはレジスタ長に依存していたよ。」
「でも今は違うよ・・・」
どうやっているのでしょうか?? 
ハードウェアに関係なく、OSやコンパイラはどのようにしてint型のサイズを決定しているのでしょうか??

int型のサイズがCPUレジスタ長に依存していないと、さらに問題が出てきます。
そう!ややこしいアライメントです。
アライメントとか、ワード境界とか

int型のサイズがハードウェアではなく、OSやコンパイラによって随時変わるのであれば、アライメントもハードウェアとは関係無いということですか??
そんなことは無いはずです。

アライメントは型のサイズごとに決められているはずです。
char = 1byte, int = 4byte
となると・・・CPUのアーキテクチャやデータバス幅やレジスタ長もアライメントには関係ないことになりませんか??

なんか・・・変ですね。
意味不明です。

アライメントは変数の型によって異なる。
では変数の型(int型やchar型)のサイズは何によって決定されているんでしょうか??

例えば、1byteの連続な列を4つまとめて、int型としたとしましょう。
ハードウェアでこれを行っているなら、OSが異なっていても、CPUが同じであれば、int型のサイズは変わらないはずですよね?
OSによって変わる・・・? どういうことでしょうか??
これはマズイですよね。
そうするとCPUごとに決められたアライメントもOSによって変わっちゃうってことですよね?
これでは読み書きの高速化には繋がらないような・・・気がしますが・・・

分かる方教えてください。
どこかにとんでもない勘違いをしている可能性があります。

[追記]
んんんん!!ああ!やっとわかったかもしれません。

「1byteの連続な列を4つまとめて、int型としたとしましょう。」
これがまさにアライメントなのですね!

つまり、4つの1byteなデータを連続して並べる事をアライメント・・・って言うんですね!
(間違っていたら教えてください。)

データ型のアラインメントとは何か,なぜ必要なのか?
アラインされていないデータへのアクセスの蘭のを見てみると、4バイトデータXがバラバラの位置に配置されていますよね。

これを、4つ連続に並べることこそがアライメントなんでしょうか??
(だとしたら、アライメントの理解を完全に間違っていたことになります。)

もしそうだとしたら・・・
いままで、こんなことを考えていました。
「4バイトのint型を連続に並べてint型のアライメントを2に小さくすれば、データを共有できるのでは?」← これ不可能ですね。

4バイトint型のアライメントを2にすると、2個の1byteが連続で並び、その2つの組は連続であることは保証されなくなる。ということですかね。
int 4byte => [1byte][1byte][   ][   ][1byte][1byte]
メモリレイアウトはこんな感じになるんですかね。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 5

checkベストアンサー

+4

こんにちは。

int型のサイズは処理系依存と言われます。しかし、この処理系依存という言葉・・・具体的に何を指しているんだろう?という疑問があります。
CPUやOS,コンパイラ・・・etc.

この場合はコンパイラです。ただ、複数の異なるCPUをサポートしているコンパイラの場合はCPUにも依存します。なお、この場合はOSには依存しません。そもそもC/C++コンパイラは基本的にはOSに依存しませんので。(でないとOSを記述することなんてできないでしょう。)

各変数のサイズやアライメントは、完全にコンパイラの設計者がそのポリシー(良心と言っても良いかも)に従って決定します。そして、その決定過程にハードウェアの制約は大きく影響します。大抵のコンパイラの設計者はコンパイルしたプログラムが高速に動作することを望みますから、ハードウェアの制約上 低速になってしまうような選択はあまりしないでしょう。(例外はあります。後述します。)

さて、64bitマシンのint型に32bitを選択するべきか64bitを選択するべきか悩ましいですね。でも、より高速になることを望むのであれば、無駄にメモリを使うよりなるべく無駄にしない方が高速です。
非常に多くのケースでint型は32bitあれば十分ですから、int型を32bitにするのはハード的にも妥当な選択ではないでしょうか?

アライメントは型のサイズごとに決められているはずです。

そんなことはありません。単に多くのCPUで型のサイズで区切った配置にすると最もアクセス性能が上がるから、そのように決められる場合が多いだけです。
例えば、奇数アドレスに2バイト整数型を配置しても速度のペナルティが全くないCPUは存在します。8bit CPUはたいてい該当します。そのようなCPUでは2バイト整数型のアライメントが0であるコンパイラしか見たことないです。

ちなみに、8bit CPUのint型は私が見たことがあるコンパイラは皆16bitでした。16bit変数アクセスは8bit変数アクセスに比べると半分の速度ですが、流石に8bitでは役に使い物にならないという判断だろうと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/07/25 07:24

    > この場合はコンパイラです。ただ、複数の異なるCPUをサポートしているコンパイラの場合はCPUにも依存します。なお、この場合はOSには依存しません。そもそもC/C++コンパイラは基本的にはOSに依存しませんので。(でないとOSを記述することなんてできないでしょう。)

    あ!なるほど!
    コンパイラなんですね。

    今まで疑問だったものが氷解しました。
    CPUは「サイズはコレコレ・・・アライメントはコレコレ」としているだけ。
    「int型」というのはコンパイラがCPUから与えられたデータ型に名前を付けているだけなんですね。

    int a = 10;
    char b = 10;

    この場合アセンブリ言語ではどちらも見分けが付かないのでは??という疑問があったのですが、
    movl $0xa,-0x4(%rbp)
    movb $0xa,-0x5(%rbp)

    ニーモニックのサフィックスが異なっていました。
    同じ値でもなんでサフィックスが異なるのか疑問だったんですよね。

    これって、int型というラベルが剥がれて、「CPUで解釈できる型」になっているわけですね。

    ということは、「コンパイラはCPUに依存している」・・・ということですかね。
    確かにこれなら、OSは議論対象から外れますね。


    > そのようなCPUでは2バイト整数型のアライメントが0であるコンパイラしか見たことないです。
    これって、つまり「アライメントなし」ということですよね??
    8bit CPUなんて見たことがない世代なので、分かりませんが、この頃にはまだアライメントなんて概念は作られていなかった時代なんですかね・・・?

    キャンセル

  • 2018/07/25 07:29

    > CPUは「サイズはコレコレ・・・アライメントはコレコレ」としているだけ。
    「int型」というのはコンパイラがCPUから与えられたデータ型に名前を付けているだけなんですね。

    64bit CPUくん「4byte, アライメント4byteというデータ型を持っていますよ。」
    コンパイラくん「じゃあ、それをint型と名付けよう・・・」
    みたいな?
    これなら、分かりやすいですね。

    CPUにはint型なんて名前は理解できないので、オペランドとニーモニックのサフィックスで「4byte, アライメント4byteというデータ型だな!」と解釈しているわけですね。

    納得いたしました。

    キャンセル

  • 2018/07/25 07:58

    https://news.mynavi.jp/article/architecture-118/
    このサイトによりますと・・・

    本来、データアライメントと命令がCISCであるかRISCであるかは殆ど独立であるが、一般的に、メモリが高価な時代に作られたCISC命令アーキテクチャではどのサイズのデータでも任意のアドレスから格納できるという構成が多く、RISCではハードの簡単化を目指すという設計思想から、2バイトデータは2の倍数、4バイトデータは4の倍数のように、データのサイズの倍数の先頭アドレスにだけ格納できるという制約が付けられることが多い。

    どうやら、昔は「任意のアドレスから格納できるという構成が多い」ようですね。
    つまり、CICS系CPUはアライメントを採用していなかった・・・ようです。

    キャンセル

  • 2018/07/25 10:39

    > 8bit CPUなんて見たことがない世代なので、分かりませんが、この頃にはまだアライメントなんて概念は作られていなかった時代なんですかね・・・?

    8bit CPUは今もバリバリ現役ですよ。
    https://ja.wikipedia.org/wiki/8%E3%83%93%E3%83%83%E3%83%88

    > つまり、CICS系CPUはアライメントを採用していなかった・・・ようです。

    「アクセスできる」と「同じ速度でアクセスできる」は異なります。
    16bitを超えるCPUのほとんどは、奇数バイト・アドレスからに格納された2バイト整数を、①そもそもアクセスできない(RISC系)、②アクセスできるけど遅い(CISC系)となります。(①はバス幅が16bitや32bitのためそもそも奇数バイト・アドレスを指定できない場合が多いです。)
    そして、8bit CPUはそもそも2バイト・アクセスは1バイト・アクセスに比べて一様に遅いですが、偶数バイト・アドレスから始まろうとそうでなかろうとそもそもアクセス単位が1バイトなので速度が遅くなることはありません。

    キャンセル

  • 2018/07/25 11:56

    「そもそもアクセス単位が1バイトなので速度が遅くなることはありません。」
    あ!そうですね。
    確かに。

    「「アクセスできる」と「同じ速度でアクセスできる」は異なります。」
    これもその通りですね。

    キャンセル

  • 2018/07/25 13:01

    あれ?
    すいません。
    そもそもなんで、データバス幅やCPUの最大レジスタ長は固定なのにもかかわらず、
    整数倍の位置に変数を配置すると高速なんでしたっけ??

    その整数倍は、変数のサイズによって異なるように見えますよね。
    char 1byte, int 4byte, long 8byte ・・・・

    それぞれアライメントはバラバラなのに、どうして整数倍の位置に配置すると高速なんでしょうか?

    キャンセル

  • 2018/07/25 13:14

    例えば、データバス幅 32bitだとすると、1回の読み書きできる量は4byteですよね??
    なのに、なぜ全ての変数は4byteアライメントではないのでしょうか??

    キャンセル

  • 2018/07/25 15:03

    > 整数倍の位置に変数を配置すると高速なんでしたっけ??

    整数倍を許せば配列にした時のメモリ効率が高いです。整数倍を許さない場合、例えば1バイトのアライメントを16ビットにする場合(そんなCPUもあったような記憶があります。大昔の記憶なので外しているかもですが)、1バイトを配列に記録する際にいちいちパディング1バイトが入るのでメモリを無駄に倍消費します。(でないと遅い、もしくは、そもそもアクセスできないわけです。後者は涙ですね。)

    整数倍ならそのような悲しい事態を回避できます。
    なので、CPUの設計者は苦労しつつ、整数倍に配置すれば高速にアクセスできるよう設計しているのではないかと思います。

    ところで、例えば32bitバスは32本の配線を使ってメモリ上の32bitを32bitレジスタへ読み出すことができます。
    16bitレジスタへ読み出す場合、メモリの上位16bitを上位16bitレジスタへ転送するために16本の配線が必要です。そしてメモリの下位16bitを上位16bitレジスタへ転送するために追加の16本の配線が必要です。
    更に、メモリの下位16bitを上位16bitレジスタ、および、下位16bitレジスタへ転送するためにそれぞれ16本の配線が必要です。都合16x4=64本の配線が必要になります。
    8bitアクセスだと更に悲惨で、4x4x8bit=128本の配線が必要になる計算です。

    最近のCPUは超高度ですので、実際にはもっと効率のよい方法で回避しているかもしれませんが、これは本質的な課題ですのでそれなりに面倒な設計をしていることは間違いないだろうと思います。

    キャンセル

  • 2018/07/25 15:17

    「メモリを無駄に倍消費します。」
    ああ、やはりここですよね。

    キャンセル

  • 2018/07/25 20:33

    解決済みになっていますが、、、
    MC68000は、CISC系ですが、アライメントありで、奇数にWordアクセスで落ちます。(例外発生) 32bitバスで、8ビットアクセスは、32bit読込みで、CPU内部で 必要な8bit取り出しなんてことやっている(のもあります)。最近は、キャッシュ有りなんで、キャッシュにまとめて読み込んで、必要なデータのみ読み込むから、あまり重要ではないですが。過去のCPUだと、アドレスそのものが、ワード(16bit)単位で、バイト(8bit)アドレスが異なるのとか。 ワードアクセスすると、最下位ビット無視なんてのありました。(例外は発生しないが、奇数アクセスは不正になる)
    そんなのでも C言語はサポートされていました。

    キャンセル

+2

C 言語における int の定義は実装依存ですが、そこには「当該CPUにとって最も自然なサイズ」という了解があります。64bit CPU であっても、実際にプログラムで利用するにあたっては 32bit サイズがあれば十分であるため、int は 32bit とするのが一般的なのです。

アライメントは CPU アーキテクチャに依存します。
古くはモトローラの MC68000 (最初期のマッキントッシュ、日本では X68000 で採用されたり、アーケードゲームの基盤にも使われた)のように、大型コンピュータから発生した CPU については、厳密なアライメントが存在しました。これは「データバス幅の倍数になるようにアクセス境界を設定する」必要がありました。
※回路の設計上の話です
簡単に言うと、奇数アドレスからのアクセスができなかった(CPUが例外を発生させる)のです。
一方 Intel はもともと 4004 CPU から発展してきた経緯もあって、こういうアクセスを許容していました。

CPU も 16bit から 32bit になり、高速化のためにキャッシュを内蔵することが当然になり、メモリアクセスも進化しました。CPU からメモリアクセスすると、ある程度のブロックを一気に読み込んで(必要か不要かは別にして)、キャッシュに置くようになります(これが可能なようにメモリ自体の設計も変化しています)。こうなると今度は、キャッシュを効率的に使用するために、「キャッシュサイズに合わせる」というアライメントが設定されるようになります。
※これには利用できるメモリ量の増大により、詰めて容量を稼ぐよりはアクセス速度を速くするほうが重要になったからでもあります

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+2

「組み込み現場のC言語」という本には

int型のサイズはビット長はレジスタ長に依存する

組み込み現場はよく知りませんが、これは真である可能性があります。組み込みだと、対象物にも依るでしょうが、抽象的なロジックを書くと言うよりは、CPUを制御するというか、高級アセンブラ的な使い方をされることが多いのではと想像します。

一般には、他の回答の通り、処理系に依存します。
また、ターゲットCPUを指定してオブジェクトを生成できる場合は、同じ処理系でもターゲットCPUによって変えることも考えられます。

「アライメント」とは、普通は、「データを複数並べるときに、次のデータを隙間無く並べるのでなく、次のデータをなにかの倍数のメモリアドレスに配置すること」です。
目的はメモリアクセスの高速化なので、その観点からはこれはターゲットCPUによって変えるべきでしょう。
0番地から始まるnバイトデータと、1番地から始まるnバイトデータの読み書きが同じCPUクロック数で行えるなら、隙間を空ける必要はありません。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/07/25 12:37

    アライメントとは、変数の配置される位置(アドレス)と直前の変数との位置関係・・・の事。と理解すればよいのでしょうか?

    キャンセル

  • 2018/07/25 12:45

    というより、何の倍数のアドレスに配置されるか、ということでしょう。

    キャンセル

  • 2018/07/25 12:49

    例えば、8バイトアライメントなら、8の倍数の任意のアドレスの位置に配置できるわけですよね?

    キャンセル

  • 2018/07/25 12:52

    そうですね。

    キャンセル

+1

int のサイズは、コンパイラの都合、でしかないです。
それ以上でも以下でもありません

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

-1

・・・やはり、アライメントの本質は、「整数倍の位置に配置されること」ではないような気がします。
レジスタ長や、データバス幅はそもそもアライメントに深く関係する話では無いですよね。

・int型4byteは、1byteが4つ並んでいます。
データ型のアラインメントとは何か,なぜ必要なのか?
こちらのサイトにも書かれているのですが・・・この1byteがもし、メモリ上に離散的に存在していたら、メモリに何度もアクセスしなくてはならなくなり、速度低下を招くわけですね。

アライメントとか、ワード境界とか

つまり・・・int型4byteをメモリ上で連続的に並ぶことを保証し、「2つの箱をまたぐような要求をしてはいけない」というアライメント制約をつけることがアライメントの本質のような気がします。

「整数倍に配置する。」や「2のべき乗」というのは、メモリを効率良く使うためのものですね。

例えば、32バイトを一度に読み込むことができるCPUがあったとして、int型4byteであれば、32バイトの中にキッチ収まります。
ところが、コレが奇数倍などになると、int型の個数が少なくとも1個は減ってしまいます。

メモリ容量の効率化すると、結果的に、CPUが一度に読み込めるint型の数を増やせることで高速化できる。
ということだと思います。

アライメントの本質は「int型4byteが離散的な位置にばらつかないこと」だと考えました。
整数倍に配置するというのは、おまけ・・・みたいな?
まぁ、こちらも重要ですかね。

レジスタ長やデータバス幅はCPUごとに異なっており、レジスタ長とデータバス幅は一致するとは限らないので、これでアライメントを考えようとすると混乱します。

ほとんど無関係だと考えられます。
だって、アライメントって変数ごとに異なり、しかも任意のアライメントを指定できる。
一方、データバス幅はCPUを購入してから動的に変わったりはしないので、ここは無関係・・・と考えるべきですね。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/07/25 15:27

    int型のサイズについては、コンパイラがCPUが持っているデータ型に名前を付けているだけ・・・と考えると分かりやすいですね。

    こちらはすぐ理解できました。

    キャンセル

  • 2018/07/25 17:05

    > アライメントの本質は「int型4byteが離散的な位置にばらつかないこと」だと考えました。
    これはアラインメントと別の話です。

    アライメントは、
    > 「2つの箱をまたぐような要求をしてはいけない」(割り当てをしてはいけない)
    ということで、つまり「箱サイズの倍数番地に割り当てる」ということとイコールです。

    キャンセル

  • 2018/07/25 17:49

    > 割り当てをしてはいけない

    あ!「2つの箱をまたぐような要求ができてしまうようなメモリ割り当てを行ってはならない」ということですね。
    それは、整数倍に変数を割り当てることで、またぐような要求に応じない。と解釈できそうですね。
    確かに、アライメント制約を満たすのでこちらが本質ということになりますね。

    キャンセル

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

  • ただいまの回答率 90.33%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • C

    3992questions

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

  • C++

    3768questions

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

  • CPU

    40questions