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

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

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

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

C++

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

Q&A

解決済

2回答

1111閲覧

C/C++における配列名(アドレス)の配置場所

退会済みユーザー

退会済みユーザー

総合スコア0

C

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

C++

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

0グッド

0クリップ

投稿2020/06/19 05:18

お世話になります。

C/C++において配列名はその配列の先頭アドレスを示しますが、
その配列名がこの先頭アドレスを示しているという情報は、
メモリのどこに配置されているものなのでしょうか?

例えば、1次元配列 testA[5]、2次元配列のtestB[3][2]の場合ですと、
testAが先頭アドレス、
testBが先頭アドレス、testB[0]、testB[1]、testB[2]が各[0][0]のアドレスを示すと思いますが、
その情報が実行ファイル内のどこにどのような情報として保管され、
及び実行中にはメモリのどこにどう展開されるのかご存知の方がおりましたがご教授頂けますと幸いです。

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

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

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

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

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

guest

回答2

0

ベストアンサー

C

1#include <stdio.h> 2 3void f(int *); 4void g(int [][2]); 5 6int testA[5]; 7int testB[3][2]; 8 9int main(void) 10{ 11 int a[5]; 12 int b[3][2]; 13 f(testA); 14 g(testB); 15 f(a); 16 g(b); 17}

これを gcc (Ubuntu 9.3.0-10ubuntu2) 9.3.0 でコンパイルすると、
次のようなコードができました。

main: endbr64 subq $72, %rsp leaq testA(%rip), %rdi # testA movq %fs:40, %rax movq %rax, 56(%rsp) xorl %eax, %eax call f@PLT leaq testB(%rip), %rdi # testB call g@PLT movq %rsp, %rdi # a call f@PLT leaq 32(%rsp), %rdi # b call g@PLT movq 56(%rsp), %rax xorq %fs:40, %rax jne .L5 xorl %eax, %eax addq $72, %rsp ret

静的な変数 testA や testB は即値ではなく、%rip(インストラクションポインタ、
すなわちプログラムカウンタ)にオフセットを加えたアドレスで参照しています。

自動変数 a や b は、%rsp(スタックポインタ) にオフセットを加えたアドレスで
参照していました。ただし、a はオフセット0 なので、%rsp の値そのものです。

いずれにせよ、配列の「アドレス」は、メモリ上にデータとして配置されているもの
ではなく、コード中にオフセットという値で保持されていることが分かりました。
ただし、これは特定のコンパイラに依存することで、他のコンパイラでは
これとは異なるやり方でアドレスを持っているかもしれません。

Visual C++ の 32ビット版は、静的変数は即値、自動変数は EBP(ベースポインタ、
すなわちフレームポインタ) にオフセットだったと思います。

また、
testB[0] は testB[0][0] のアドレスに変換されますが、
testB[1] は testB[1][0] のアドレスに、そして、
testB[2] は testB[2][0] のアドレスに変換されます。

追記
Visual C++ の 32ビット版で -FAオプションでコンパイルすると、

_DATA SEGMENT COMM _testA:DWORD:05H COMM _testB:DWORD:06H _DATA ENDS PUBLIC _main EXTRN _f:PROC EXTRN _g:PROC EXTRN @__security_check_cookie@4:PROC EXTRN ___security_cookie:DWORD ; Function compile flags: /Odtp _TEXT SEGMENT _b$ = -48 ; size = 24 _a$ = -24 ; size = 20 __$ArrayPad$ = -4 ; size = 4 _main PROC ; File c:\tmp\c\a.c ; Line 10 push ebp mov ebp, esp sub esp, 48 ; 00000030H mov eax, DWORD PTR ___security_cookie xor eax, ebp mov DWORD PTR __$ArrayPad$[ebp], eax ; Line 13 push OFFSET _testA call _f add esp, 4 ; Line 14 push OFFSET _testB call _g add esp, 4 ; Line 15 lea eax, DWORD PTR _a$[ebp] push eax call _f add esp, 4 ; Line 16 lea ecx, DWORD PTR _b$[ebp] push ecx call _g add esp, 4 ; Line 17 xor eax, eax mov ecx, DWORD PTR __$ArrayPad$[ebp] xor ecx, ebp call @__security_check_cookie@4 mov esp, ebp pop ebp ret 0 _main ENDP _TEXT ENDS END

投稿2020/06/21 18:14

編集2020/06/22 01:23
kazuma-s

総合スコア8224

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

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

退会済みユーザー

退会済みユーザー

2020/06/22 01:17

ご返信いただきましてありがとうございます。 詳細なご説明、ありがとうございます。 コンパイラ依存の部分が大きいのですね。ただし、配列名でアドレスを指定したとしても、メモリ上に配列名でアドレスを保持しているような変数(又は変数のような領域)は無く、ベースとなるアドレス+オフセットのコードに変換されているのですね。 大変参考になりました。ありがとうございました。
guest

0

その配列名がこの先頭アドレスを示しているという情報は、

メモリのどこに配置されているものなのでしょうか?

即値としてコード内に埋め込まれます。データメモリ側で持つものではありません。

投稿2020/06/19 05:20

maisumakun

総合スコア146018

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

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

maisumakun

2020/06/19 05:21

メモリレイアウトはコンパイル時に確定しますので、そこでアドレスとしてコードに埋め込んでしまいます。
退会済みユーザー

退会済みユーザー

2020/06/19 06:51

ご返信ありがとうございます。 コンパイル時に、testAと書かれているコードのところは、testAが指し示す先頭アドレス(直値)で書き換わり、先頭アドレスを保持しているtestAという領域が存在するわけではないということで合っておりますでしょうか? お手数お掛けしますが宜しくお願いします。
maisumakun

2020/06/19 06:52

そのとおりです。変数や配列という概念はコンパイラが見せているものに過ぎず、コンパイル後にはメモリアドレスだけが並ぶ状態になります。
退会済みユーザー

退会済みユーザー

2020/06/19 06:57

ご返信ありがとうございます。 なるほど、承知しました。大変助かりました。 諸々のご説明ありがとうございます。 今後も何か機会が御座いましたら、お助け頂けますと幸いです。
退会済みユーザー

退会済みユーザー

2020/06/19 08:13

追加での質問となり恐縮ですが、 関数等でのローカル変数で配列変数を宣言した場合、 その場合は、配列が、実行中のその時のスタックの一番上に積まれるかと思いますが、 この際にこの配列の配列名を使った場合はどのような扱いとなりますでしょうか? お手数お掛けしますが、宜しくお願い申し上げます。
kazuma-s

2020/06/19 08:35 編集

ローカル変数が自動変数なら、フレームポインタとオフセットで実行時に計算されます。コードに即値で埋め込まれるのは、静的変数の場合です。
退会済みユーザー

退会済みユーザー

2020/06/19 17:35

ご返信ありがとうございます。 配列をローカル変数の自動変数で宣言した場合は、 コードで配列名を使い、何かしらの処理をしてる箇所において、 配列名がフレームポインタにオフセットを足すコードに置き換わっているという解釈でよろしいでしょうか? よろしくお願い申し上げます。
退会済みユーザー

退会済みユーザー

2020/06/21 13:19

お手数お掛けしますが、もし解釈が間違っておりましたがご指摘頂けると幸いです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問