変数の名前と値の関係を教えてほしいです!

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
tokyo_kyoto_
記事: 4
登録日時: 6年前

変数の名前と値の関係を教えてほしいです!

#1

投稿記事 by tokyo_kyoto_ » 6年前

こんにちは、早速なんですが、下の例を見てほしいです。int型の変数aが123で、初期化されています。参考書などで、このことを、aという名前のint型の箱に値123が入れられると表現されることが多いのですが、このとき、aと123の関係はどうなっているのでしょうか?普通に考えれば、a=123で終わりじゃないのと、思いますが、実際のところ、名前aと値123は別々のアドレスの場所に保存されていますし、この点いまいちわかりません。

コード:

int a = 123;
現在、柴田望洋さんの新明解C言語・入門編を読み解き終わったところなんですが、ポインタのところで、違和感を感じています。その理由は、この質問にあると思っています。(例えば、&aは名前aか値123のどっちのアドレスのことを指しているのか、わかりません。)どなたか、aと123の関係を教えてほしいです。ご返答よろしくお願いします。

Math

Re: 変数の名前と値の関係を教えてほしいです!

#2

投稿記事 by Math » 6年前

Windows10,VS2017Communityの場合
下記のCをアセンブルすると

コード:

nt main(void){

	int a = 123;

	return 0;
アセンブラーに変換したコード

コード:

; 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
この様に123(0000007bH)は即値 【 immediate 】 イミディエイト ( 即値オペランド / immediate operand / 直値 ) です。

即値とは、アセンブリ言語や機械語で、命令が扱う対象となるデータ(オペランド)としてコード中に直に書き込まれた数値のこと。メモリやレジスタなどから読み出した値ではなく、コード中で命令語の直後に置かれている値であることからこのように呼ばれる。

(また、高水準言語でソースコード中に直に書き込まれたデータのことや、そのようなデータの記述形式を即値ということがあるが、こちらは「リテラル」(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

Math

Re: 変数の名前と値の関係を教えてほしいです!

#3

投稿記事 by Math » 6年前

またインラインアセンブラーで書くと(Windows10、VS2017Communityを使用している)

コード:

#include <stdio.h>

int main(void) {

	int a;

	__asm mov a,123

	printf("a=%d\n", a);

	return 0;
}
実行結果

コード:

a=123
続行するには何かキーを押してください . . .

tokyo_kyoto_
記事: 4
登録日時: 6年前

Re: 変数の名前と値の関係を教えてほしいです!

#4

投稿記事 by tokyo_kyoto_ » 6年前

Math さんが書きました: &aは名前aのアドレスを指していて*(&a)つまりaは値123をもっています。
aは値123をもっている、というのがわかりません。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/

***********************************************************************************************************/

Math

Re: 変数の名前と値の関係を教えてほしいです!

#5

投稿記事 by Math » 6年前

今時間がないので簡単に説明すれば”関数”は呼ばれた時点で存在し、関数を抜けた時点で消滅します。push ebpと pop ebpのペアで元のプログラム位置に返ることが出来ます。
変数aはmov DWORD PTR _a$[ebp], 123 ; 0000007bHによって アドレス&aに(Windows10 はリトルエンディアンとして)4バイト型整数(int型)として格納されます。
ーーーーーー
MOV DEST,SRC
動作:DEST←SRC
影響を受けるフラグ:なし
DEST:レジスタ、メモリー
SRC :レジスタ、メモリー、即値(ただしメモリー、メモリーの組み合わせは除く)
ーーーーーー

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: 変数の名前と値の関係を教えてほしいです!

#6

投稿記事 by みけCAT » 6年前

aはプログラマ用の名前で、コンパイラがスタック上の適当な場所(ベースポインタebpからのオフセット)を割り当てます。
今回はebp-4に割り当てられたようです。
実行時には必要ないので、格納されないかデバッグ用の情報を入れる場所に格納されます。

123は実行時に使われるint型のデータで、レジズタに入ったりメモリに入ったりします。

今回の場合、mov dword ptr [ebp-4],7Bhを実行した時点で、スタックは以下のようになるでしょう。
push ecxのecxにあまり意味はなく、「espを4減らしてローカル変数を入れる領域を確保する」という意味で使われていますね。

コード:

      ┌────┐
      │他データ│
      ├────┤
      │他データ│
      ├────┤
      │戻り番地│
      ├────┤
ebp →│前のebp │
      ├────┤
esp →│123     │← a
      ├────┤
      │        │
      └────┘
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

tokyo_kyoto_
記事: 4
登録日時: 6年前

Re: 変数の名前と値の関係を教えてほしいです!

#7

投稿記事 by tokyo_kyoto_ » 6年前

メインメモリとスタックに何もデータが入ってない、超理想的な状況で、これまでのことを書いてみたのですが、合っているでしょうか?
(esp,ebpはそれぞれ100としました)
こうすれば、レジスタになれなかった変数たちも、レジスタのように扱えると思うのですが…(あとはコンパイラ次第)
添付ファイル
tokyo_kyoto_001.pdf
(1.11 MiB) ダウンロード数: 217 回

sleep

Re: 変数の名前と値の関係を教えてほしいです!

#8

投稿記事 by sleep » 6年前

tokyo_kyoto_ さんが書きました: 実際のところ、名前aと値123は別々のアドレスの場所に保存されていますし、この点いまいちわかりません。
最初、上の文章が何を言っているのかさっぱり分かりませんでしたが
おそらく、&aで返されてきたアドレスの値とメモリビューア等で確認したときの7bHの格納されている位置で場所にズレがある、的な話をされてるんでしょうね。(ただ、実際はIntel製のCPUのバイトオーダーはリトルエンディアンなので&aのアドレスのbyteに7bが入っていて、7b 00 00 00 となっているはずですが)

それを前提として話をします。

以下の2つは同じことを表現していますが

コード:

_a$ = -4						; size = 4
mov	DWORD PTR _a$[ebp], 123		; 0000007bH

コード:

mov DWORD PTR [ebp-4], 7bH
重要なことは、即値をメモリへストアする際は、場所とサイズの指定が必要であるということです。
PTR演算子の前にDWORDという単語がありますが、これは4byteを表しています。
つまり、仮想メモリの[ebp-4]の場所から4byte分の広さを使用して7bHという値を格納(保持)してください、という意味です。(具体的には、[ebp-4]から4byteを使用して0000007bH が表現できればいい)

メモリでは1つのアドレスが示す先には、1byte分のサイズの領域しか存在しません。
なので、1つのアドレスが示す先に、宣言した変数毎に色んな明確なサイズの領域がぶら下がってるわけではありません。
そのため、その場所から何byte分(言い換えると何アドレス分)を1つの変数としてみなして使用することにするのかというサイズの指定が重要となります。

int a の &a が 0x0073f8d8 のアドレスを指していたら、int a = 123; (0000007bH)は、以下のように仮想メモリへと格納されます。

コード:

0x0073f8d8 7b
0x0073f8d9 00
0x0073f8dA 00
0x0073f8dB 00
int a という宣言は、結果的にディスプレースメントで確保するサイズが4であることを示しています。そのため

コード:

_a$ = -4						; size = 4
などというエイリアスになっています。
movによるデータのストアで、オフセットアドレスに使用できるレジスタは決まっています。ebpはその内の1つです。
ebpは関数呼び出し時のスタック領域のベースアドレスとして使用されます。
つまり、変数 a はmain関数で使用されているスタック領域に[ebp-4]の位置から4byte分のサイズで確保されたことになっている、ということになります。(4byteのサイズを超過して書き込むこともできてしまう)
レジスタは1つ1つのサイズが決まっていますが、メモリは場所こそ指定できるもののサイズは決まっていません。(また、即値のサイズも決まっていない)
メモリへストアする際にサイズの指定が重要となるのはこのためです。
 

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: 変数の名前と値の関係を教えてほしいです!

#9

投稿記事 by みけCAT » 6年前

tokyo_kyoto_ さんが書きました:メインメモリとスタックに何もデータが入ってない、超理想的な状況で、これまでのことを書いてみたのですが、合っているでしょうか?
x86では同じアドレスの数字で「メインメモリ」と「スタック」に分かれるということはなく、メインメモリの一部をスタックとして使用するはずです。
図の意味を説明していただけますか?
tokyo_kyoto_ さんが書きました:こうすれば、レジスタになれなかった変数たちも、レジスタのように扱えると思うのですが…(あとはコンパイラ次第)
申し訳ありません。意味がよくわかりません。
「こうすれば」とはどうすることでしょうか?
「レジスタのように扱える」というのは、レジスタのどのような性質を仮想的に実現するということでしょうか?
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

ISLe
記事: 2650
登録日時: 13年前
連絡を取る:

Re: 変数の名前と値の関係を教えてほしいです!

#10

投稿記事 by ISLe » 6年前

オフトピック
アセンブラの話で盛り上がっているのでこちらはオフトピで。

質問の後半に「ポインタのところで、違和感を感じています」とあるので、変数名が即値にバインドされるという勘違いから生じている疑問ではないのかなあ。
ポインタが分からないという理由によくある話だと思う。

int a = 123;
という変数の宣言の中身としては、
1. int型の値を格納できる大きさの記憶域が確保される。この記憶域は生存期間中一定のアドレスを持つ。
2. 1.で確保された記憶域をaという名前で(アドレスを使うでなく)アクセスできる
3. 1.で確保した記憶域は初期段階で123という値を持つ
というふうだけれど、特に初心者向けの解説だと1.が省略される。

だから、もともと123という値があるところをaという名前で読み書きできるようにする、みたいな勘違いが起きる。

&aは1.にある、aが示す記憶域のアドレスを取得する手段。
名前aのアドレスでも値123のアドレスでもない。

これをきちんと理解すれば、アドレスを記憶域に格納するポインタの理解もスムーズにいくはず、だといいけれど。

tokyo_kyoto_
記事: 4
登録日時: 6年前

Re: 変数の名前と値の関係を教えてほしいです!

#11

投稿記事 by tokyo_kyoto_ » 6年前

Mathさん、みけCATさん、sleepさん、ISLeさん
わかりやすい返答ありがとうございます。とてもいい話ができたと思っています。変数の名前は主にアクセス用に使うことがよくわかりました。

僕は今、ハードウェアとソフトウェアの両方からパソコンを理解しようとしているのですが、よくその両方がどうつながっているのか疑問に思うことがあります。今回の質問は、おそらくその中間にあるものだと思います。(だから難しい)

今後も勉強をがんばっていくのですが、google先生でもわからないことがあれば、どんどん質問していくので、その時は、よろしくお願いします。

返信

“C言語何でも質問掲示板” へ戻る