変数の名前と値の関係を教えてほしいです!
-
- 記事: 4
- 登録日時: 6年前
変数の名前と値の関係を教えてほしいです!
こんにちは、早速なんですが、下の例を見てほしいです。int型の変数aが123で、初期化されています。参考書などで、このことを、aという名前のint型の箱に値123が入れられると表現されることが多いのですが、このとき、aと123の関係はどうなっているのでしょうか?普通に考えれば、a=123で終わりじゃないのと、思いますが、実際のところ、名前aと値123は別々のアドレスの場所に保存されていますし、この点いまいちわかりません。
現在、柴田望洋さんの新明解C言語・入門編を読み解き終わったところなんですが、ポインタのところで、違和感を感じています。その理由は、この質問にあると思っています。(例えば、&aは名前aか値123のどっちのアドレスのことを指しているのか、わかりません。)どなたか、aと123の関係を教えてほしいです。ご返答よろしくお願いします。
現在、柴田望洋さんの新明解C言語・入門編を読み解き終わったところなんですが、ポインタのところで、違和感を感じています。その理由は、この質問にあると思っています。(例えば、&aは名前aか値123のどっちのアドレスのことを指しているのか、わかりません。)どなたか、aと123の関係を教えてほしいです。ご返答よろしくお願いします。
Re: 変数の名前と値の関係を教えてほしいです!
Windows10,VS2017Communityの場合
下記のCをアセンブルすると アセンブラーに変換したコード
この様に123(0000007bH)は即値 【 immediate 】 イミディエイト ( 即値オペランド / immediate operand / 直値 ) です。
即値とは、アセンブリ言語や機械語で、命令が扱う対象となるデータ(オペランド)としてコード中に直に書き込まれた数値のこと。メモリやレジスタなどから読み出した値ではなく、コード中で命令語の直後に置かれている値であることからこのように呼ばれる。
(また、高水準言語でソースコード中に直に書き込まれたデータのことや、そのようなデータの記述形式を即値ということがあるが、こちらは「リテラル」(literal)と呼ぶのが一般的である。)
&aは名前aのアドレスを指していて*(&a)つまりaは値123をもっています。
Dumpすると
下記のCをアセンブルすると アセンブラーに変換したコード
; Listing generated by Microsoft (R) Optimizing Compiler Version 19.10.25019.0
TITLE D:\z17c\c\0915\c1.c
.686P
.XMM
include listing.inc
.model flat
INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES
PUBLIC _main
; Function compile flags: /Odtp
_TEXT SEGMENT
_a$ = -4 ; size = 4
_main PROC
; File d:\z17c\c\0915\c1.c
; Line 1
push ebp
mov ebp, esp
push ecx
; Line 3
mov DWORD PTR _a$[ebp], 123 ; 0000007bH
; Line 5
xor eax, eax
; Line 6
mov esp, ebp
pop ebp
ret 0
_main ENDP
_TEXT ENDS
END
即値とは、アセンブリ言語や機械語で、命令が扱う対象となるデータ(オペランド)としてコード中に直に書き込まれた数値のこと。メモリやレジスタなどから読み出した値ではなく、コード中で命令語の直後に置かれている値であることからこのように呼ばれる。
(また、高水準言語でソースコード中に直に書き込まれたデータのことや、そのようなデータの記述形式を即値ということがあるが、こちらは「リテラル」(literal)と呼ぶのが一般的である。)
&aは名前aのアドレスを指していて*(&a)つまりaは値123をもっています。
Dumpすると
D:\z17c\c\0915>dumpbin /DISASM c1.exe
Microsoft (R) COFF/PE Dumper Version 14.10.25019.0
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file c1.exe
File Type: EXECUTABLE IMAGE
00401000: 55 push ebp
00401001: 8B EC mov ebp,esp
00401003: 51 push ecx
00401004: C7 45 FC 7B 00 00 mov dword ptr [ebp-4],7Bh
00
0040100B: 33 C0 xor eax,eax
0040100D: 8B E5 mov esp,ebp
0040100F: 5D pop ebp
00401010: C3 ret
00401011: 56 push esi
-
- 記事: 4
- 登録日時: 6年前
Re: 変数の名前と値の関係を教えてほしいです!
aは値123をもっている、というのがわかりません。aと123の具体的な関係を知りたいのです。Math さんが書きました: &aは名前aのアドレスを指していて*(&a)つまりaは値123をもっています。
また、Mathさんのアセンブリを、考えてみたんですけど、間違い・補足があれば訂正お願いします!
push ebp //レジスタespの値が4減らし、レジスタespの値が示すスタックのアドレスにレジスタebpの値が保存される。
mov ebp,esp //レジスタespの値をレジスタebpに代入する。
push ecx //レジスタespの値が4減らし、レジスタespの値が示すスタックのアドレスにレジスタecxの値が保存される。
mov dword ptr [ebp-4],7Bh //(レジスタebpの値-4)が示すメモリのアドレスに123を代入する。
xor eax,eax //レジスタeaxの値を0にする。(eaxはアキュームレータレジスタ)
mov esp,ebp //レジスタebpの値をレジスタespに代入する。
pop ebp //レジスタespの値が示すスタックのアドレスにあるデータがレジスタebpに代入され、レジスタespの値が4増える。
ret //return 0?
push esi //レジスタespの値が4減らし、レジスタespの値が示すスタックのアドレスにレジスタesiの値が保存される。
/**********************************************************************************************************
参考文献
アセンブリ言語の基礎 http://hp.vector.co.jp/authors/VA014520/asmhsp/chap2.html
プログラマの友 http://www7b.biglobe.ne.jp/~robe/pf/
Programming Room http://ings.sakura.ne.jp/prog/
***********************************************************************************************************/
Re: 変数の名前と値の関係を教えてほしいです!
今時間がないので簡単に説明すれば”関数”は呼ばれた時点で存在し、関数を抜けた時点で消滅します。push ebpと pop ebpのペアで元のプログラム位置に返ることが出来ます。
変数aはmov DWORD PTR _a$[ebp], 123 ; 0000007bHによって アドレス&aに(Windows10 はリトルエンディアンとして)4バイト型整数(int型)として格納されます。
ーーーーーー
MOV DEST,SRC
動作:DEST←SRC
影響を受けるフラグ:なし
DEST:レジスタ、メモリー
SRC :レジスタ、メモリー、即値(ただしメモリー、メモリーの組み合わせは除く)
ーーーーーー
変数aはmov DWORD PTR _a$[ebp], 123 ; 0000007bHによって アドレス&aに(Windows10 はリトルエンディアンとして)4バイト型整数(int型)として格納されます。
ーーーーーー
MOV DEST,SRC
動作:DEST←SRC
影響を受けるフラグ:なし
DEST:レジスタ、メモリー
SRC :レジスタ、メモリー、即値(ただしメモリー、メモリーの組み合わせは除く)
ーーーーーー
Re: 変数の名前と値の関係を教えてほしいです!
aはプログラマ用の名前で、コンパイラがスタック上の適当な場所(ベースポインタebpからのオフセット)を割り当てます。
今回はebp-4に割り当てられたようです。
実行時には必要ないので、格納されないかデバッグ用の情報を入れる場所に格納されます。
123は実行時に使われるint型のデータで、レジズタに入ったりメモリに入ったりします。
今回の場合、mov dword ptr [ebp-4],7Bhを実行した時点で、スタックは以下のようになるでしょう。
push ecxのecxにあまり意味はなく、「espを4減らしてローカル変数を入れる領域を確保する」という意味で使われていますね。
今回はebp-4に割り当てられたようです。
実行時には必要ないので、格納されないかデバッグ用の情報を入れる場所に格納されます。
123は実行時に使われるint型のデータで、レジズタに入ったりメモリに入ったりします。
今回の場合、mov dword ptr [ebp-4],7Bhを実行した時点で、スタックは以下のようになるでしょう。
push ecxのecxにあまり意味はなく、「espを4減らしてローカル変数を入れる領域を確保する」という意味で使われていますね。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)
-
- 記事: 4
- 登録日時: 6年前
Re: 変数の名前と値の関係を教えてほしいです!
メインメモリとスタックに何もデータが入ってない、超理想的な状況で、これまでのことを書いてみたのですが、合っているでしょうか?
(esp,ebpはそれぞれ100としました)
こうすれば、レジスタになれなかった変数たちも、レジスタのように扱えると思うのですが…(あとはコンパイラ次第)
(esp,ebpはそれぞれ100としました)
こうすれば、レジスタになれなかった変数たちも、レジスタのように扱えると思うのですが…(あとはコンパイラ次第)
- 添付ファイル
-
- tokyo_kyoto_001.pdf
- (1.11 MiB) ダウンロード数: 226 回
Re: 変数の名前と値の関係を教えてほしいです!
最初、上の文章が何を言っているのかさっぱり分かりませんでしたがtokyo_kyoto_ さんが書きました: 実際のところ、名前aと値123は別々のアドレスの場所に保存されていますし、この点いまいちわかりません。
おそらく、&aで返されてきたアドレスの値とメモリビューア等で確認したときの7bHの格納されている位置で場所にズレがある、的な話をされてるんでしょうね。(ただ、実際はIntel製のCPUのバイトオーダーはリトルエンディアンなので&aのアドレスのbyteに7bが入っていて、7b 00 00 00 となっているはずですが)
それを前提として話をします。
以下の2つは同じことを表現していますが 重要なことは、即値をメモリへストアする際は、場所とサイズの指定が必要であるということです。
PTR演算子の前にDWORDという単語がありますが、これは4byteを表しています。
つまり、仮想メモリの[ebp-4]の場所から4byte分の広さを使用して7bHという値を格納(保持)してください、という意味です。(具体的には、[ebp-4]から4byteを使用して0000007bH が表現できればいい)
メモリでは1つのアドレスが示す先には、1byte分のサイズの領域しか存在しません。
なので、1つのアドレスが示す先に、宣言した変数毎に色んな明確なサイズの領域がぶら下がってるわけではありません。
そのため、その場所から何byte分(言い換えると何アドレス分)を1つの変数としてみなして使用することにするのかというサイズの指定が重要となります。
int a の &a が 0x0073f8d8 のアドレスを指していたら、int a = 123; (0000007bH)は、以下のように仮想メモリへと格納されます。 int a という宣言は、結果的にディスプレースメントで確保するサイズが4であることを示しています。そのため などというエイリアスになっています。
movによるデータのストアで、オフセットアドレスに使用できるレジスタは決まっています。ebpはその内の1つです。
ebpは関数呼び出し時のスタック領域のベースアドレスとして使用されます。
つまり、変数 a はmain関数で使用されているスタック領域に[ebp-4]の位置から4byte分のサイズで確保されたことになっている、ということになります。(4byteのサイズを超過して書き込むこともできてしまう)
レジスタは1つ1つのサイズが決まっていますが、メモリは場所こそ指定できるもののサイズは決まっていません。(また、即値のサイズも決まっていない)
メモリへストアする際にサイズの指定が重要となるのはこのためです。
Re: 変数の名前と値の関係を教えてほしいです!
x86では同じアドレスの数字で「メインメモリ」と「スタック」に分かれるということはなく、メインメモリの一部をスタックとして使用するはずです。tokyo_kyoto_ さんが書きました:メインメモリとスタックに何もデータが入ってない、超理想的な状況で、これまでのことを書いてみたのですが、合っているでしょうか?
図の意味を説明していただけますか?
申し訳ありません。意味がよくわかりません。tokyo_kyoto_ さんが書きました:こうすれば、レジスタになれなかった変数たちも、レジスタのように扱えると思うのですが…(あとはコンパイラ次第)
「こうすれば」とはどうすることでしょうか?
「レジスタのように扱える」というのは、レジスタのどのような性質を仮想的に実現するということでしょうか?
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)
Re: 変数の名前と値の関係を教えてほしいです!
オフトピック
アセンブラの話で盛り上がっているのでこちらはオフトピで。
質問の後半に「ポインタのところで、違和感を感じています」とあるので、変数名が即値にバインドされるという勘違いから生じている疑問ではないのかなあ。
ポインタが分からないという理由によくある話だと思う。
int a = 123;
という変数の宣言の中身としては、
1. int型の値を格納できる大きさの記憶域が確保される。この記憶域は生存期間中一定のアドレスを持つ。
2. 1.で確保された記憶域をaという名前で(アドレスを使うでなく)アクセスできる
3. 1.で確保した記憶域は初期段階で123という値を持つ
というふうだけれど、特に初心者向けの解説だと1.が省略される。
だから、もともと123という値があるところをaという名前で読み書きできるようにする、みたいな勘違いが起きる。
&aは1.にある、aが示す記憶域のアドレスを取得する手段。
名前aのアドレスでも値123のアドレスでもない。
これをきちんと理解すれば、アドレスを記憶域に格納するポインタの理解もスムーズにいくはず、だといいけれど。
質問の後半に「ポインタのところで、違和感を感じています」とあるので、変数名が即値にバインドされるという勘違いから生じている疑問ではないのかなあ。
ポインタが分からないという理由によくある話だと思う。
int a = 123;
という変数の宣言の中身としては、
1. int型の値を格納できる大きさの記憶域が確保される。この記憶域は生存期間中一定のアドレスを持つ。
2. 1.で確保された記憶域をaという名前で(アドレスを使うでなく)アクセスできる
3. 1.で確保した記憶域は初期段階で123という値を持つ
というふうだけれど、特に初心者向けの解説だと1.が省略される。
だから、もともと123という値があるところをaという名前で読み書きできるようにする、みたいな勘違いが起きる。
&aは1.にある、aが示す記憶域のアドレスを取得する手段。
名前aのアドレスでも値123のアドレスでもない。
これをきちんと理解すれば、アドレスを記憶域に格納するポインタの理解もスムーズにいくはず、だといいけれど。
-
- 記事: 4
- 登録日時: 6年前
Re: 変数の名前と値の関係を教えてほしいです!
Mathさん、みけCATさん、sleepさん、ISLeさん
わかりやすい返答ありがとうございます。とてもいい話ができたと思っています。変数の名前は主にアクセス用に使うことがよくわかりました。
僕は今、ハードウェアとソフトウェアの両方からパソコンを理解しようとしているのですが、よくその両方がどうつながっているのか疑問に思うことがあります。今回の質問は、おそらくその中間にあるものだと思います。(だから難しい)
今後も勉強をがんばっていくのですが、google先生でもわからないことがあれば、どんどん質問していくので、その時は、よろしくお願いします。
わかりやすい返答ありがとうございます。とてもいい話ができたと思っています。変数の名前は主にアクセス用に使うことがよくわかりました。
僕は今、ハードウェアとソフトウェアの両方からパソコンを理解しようとしているのですが、よくその両方がどうつながっているのか疑問に思うことがあります。今回の質問は、おそらくその中間にあるものだと思います。(だから難しい)
今後も勉強をがんばっていくのですが、google先生でもわからないことがあれば、どんどん質問していくので、その時は、よろしくお願いします。