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

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

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

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

Q&A

解決済

7回答

3897閲覧

変数がメモリに格納される順番が変わらない

Prometheus

総合スコア10

C

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

0グッド

1クリップ

投稿2020/06/27 04:33

前提・実現したいこと

変数宣言の順番によって、変数がメモリアドレスに格納される順番が変わることを確認するために、
int型変数のiと、char型変数のcを、それぞれ順番を変えて宣言したのですが、
メモリアドレスに格納される順番が変わっていませんでした。
理由を教えて頂きたいです。

発生している問題・エラーメッセージ

変数cを先に宣言した場合

terminal

1ronin@ronin-ThinkPad-X280:~/Program$ gcc sample.c 2ronin@ronin-ThinkPad-X280:~/Program$ ./a.out 3変数iのアドレス 0x7ffe1c7df634 4変数cのアドレス 0x7ffe1c7df633 5

変数iを先に宣言した場合

terminal

1ronin@ronin-ThinkPad-X280:~/Program$ gcc sample.c 2ronin@ronin-ThinkPad-X280:~/Program$ ./a.out 3変数iのアドレス 0x7ffc0d5a2ee4 4変数cのアドレス 0x7ffc0d5a2ee3

該当のソースコード

変数cを先に宣言

C

1#include <stdio.h> 2 3int main(){ 4 char c; 5 int i; 6 7 printf("変数iのアドレス %p\n", &i); 8 printf("変数cのアドレス %p\n", &c); 9} 10

変数iを先に宣言

C

1#include <stdio.h> 2 3int main(){ 4 int i; 5 char c; 6 7 printf("変数iのアドレス %p\n", &i); 8 printf("変数cのアドレス %p\n", &c); 9} 10

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

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

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

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

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

YT0014

2020/06/27 04:44

>変数宣言の順番によって、変数がメモリアドレスに格納される順番が変わる そもそも、変数がメモリに配置される保証すらないんですが。 その情報のソースをご提示ください。 多分、関数の外で宣言したら、順番通りになるとは思いますが、コンパイル環境によっては、それも崩れるかと。
Prometheus

2020/06/27 04:51

『HACKING:美しき策謀』という本のp145~146を参考にしました。
guest

回答7

0

ベストアンサー

宣言順とアドレスに関係はありません。どのように配置されるかはコンパイラに任されます。4 バイトのメモリが後に(スタックなので後ろから数える)確保されているのは、パフォーマンス上の理由による最適化の結果だと思います。詳しくは次を参照してください。

データ構造アライメント - Wikipedia

投稿2020/06/27 04:38

編集2020/06/27 04:41
Zuishin

総合スコア28656

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

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

Prometheus

2020/06/27 04:55

回答ありがとうございます。 変数の大きさによってアドレスが順序付けられるなど、かなり柔軟に対応してくれるのですね。
Zuishin

2020/06/27 04:59

してくれるコンパイラ「も」あります。うろ覚えですが、Visual Studio と gcc はしてたと思います。色々なサイズの変数を定義して検証してみてください。
guest

0

各変数が実メモリ上にどう配置されるかは言語仕様では規定していません。
つまりコンパイラの勝手.

投稿2020/06/27 04:39

episteme

総合スコア16614

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

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

episteme

2020/06/27 04:41

...かぶりまくりー^^;
InNELV

2020/06/27 04:52

ですね。 ;^^
Prometheus

2020/06/27 04:53

回答ありがとうございます。 変数の宣言順は関係ないのですね。
guest

0

「変数がメモリアドレスに格納される順番」は、処理系・コンパイラ・リンカ、さらに最適化の有無等によって変わります。

 なので、どういう順番でアドレッシングされるかも、決まった答えはありません。

投稿2020/06/27 04:39

showkit

総合スコア1638

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

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

Prometheus

2020/06/27 04:54

回答ありがとうございます。 変数の宣言順は関係ないのですね。
episteme

2020/06/27 06:56

関係ないとは言えない、と推測されます。 アライメントの変化しない、たとえば int a, b, c, d; と int d, c, b, a; なら宣言順に依存しそう。
showkit

2020/06/27 07:17

そうですね「関係ない」ということではありません。関係はあって、変数の宣言順は影響したりしますが・・・。 「アライメントの変化しない、たとえば int a, b, c, d; と int d, c, b, a; なら宣言順に依存しそう。」ではありますが、そういう限定的な宣言の話でなければ、結局、一般的に宣言順による「決まった答え」はありません。
guest

0

オプティマイズやコンパイラの仕様などにもよりますが、想定される動作は、いかのようなものかと。

C

1 int i; /* レジスタ変数に仮設定 */ 2 char c; /* レジスタ変数に仮設定 */ 3 4 printf("変数iのアドレス %p\n", &i); /* スタック変数に決定 */ 5 printf("変数cのアドレス %p\n", &c); /* スタック変数に決定 */

コンパイラが、スタック変数に決定した順番で決めていたら、ご提示のような結果になるでしょう。

余談
とあるCの一部のバージョンで、初期化文字列に文字数制限があったことがあります。
それを超える文字列を使いたいとき、このコンパイラのchar配列のメモリ配置が連続することを利用して、以下のようなコードを使っていました。

C

1int hoge() { 2 static char message[20] = "限界までの文字列です"; 3 static char dummy[] = "追加文字列。"; 4 message[20] = 0x20; 5} 6

投稿2020/06/27 04:50

編集2020/06/27 05:52
YT0014

総合スコア1708

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

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

Zuishin

2020/06/27 04:53

printf の順番によってアドレスが変わるということでしょうか?
YT0014

2020/06/27 04:59

そういう可能性もある、というだけで、未検証です。 アライメントの可能性の方が高そうですが。
Zuishin

2020/06/27 05:01

割り当ての前に構文木を作るものが多いんじゃないかと思うので、疑問でした。ありがとうございます。
guest

0

「メモリアドレスにどのように配置されるか」
はコンパイラとコンパイル時の指定・実行系に依存すると思います。
構造体・配列であれば確認できるのではないでしょうか。
(メインフレームのCOBOLは、記述順にアロケートされましたが)

投稿2020/06/27 04:43

InNELV

総合スコア31

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

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

Prometheus

2020/06/27 04:52

回答ありがとうございます。 コンパイラの問題なのですね。
InNELV

2020/06/27 04:54

はい。ですが、確認してみよう という試みは面白いと思います。
guest

0

回答はされているのですが、質問の意図が、アドレス指定したいのであれば、
構造体を使うと可能かと思います。

しかし、目的は?

投稿2020/06/30 04:58

herobo

総合スコア153

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

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

Prometheus

2020/06/30 05:29 編集

CTFの勉強のために、スタックバッファオーバーフローによって、変数領域を上書きしようとしました。 変数の宣言の順序によって、変数がメモリに格納される順番が変わるという趣旨の記述が、『HACKING:美しき策謀』に記載されていたため、自分の環境ではなぜ出来ないのか気になり、質問しました。
Zuishin

2020/06/30 05:54

ひょっとしてローカル変数でなく引数ではありませんか? それなら宣言順にスタックに積まれますし、関数外部からインジェクションできます。
herobo

2020/06/30 23:55

スタックバッファオーバーフローの実験なら、同じ形の変数であれば再現するかも。
guest

0

コメントにしようかと思ったのですが、、、

他の人の回答どおりですが、参考として、、

例えば、データバスが 4バイトの時、 1byte(+3byte), 4byte, 1byteでは効率悪すぎです。どこまで効率良くは別ですが、大抵のコンパイラはやってるのではないとか思います。
その一方、この無駄で運よく動いてたコードもある. (char[1]なのに、4文字までOKとか...) バグなのですが、動いているコードで触れなかった。

また、メモリの確保は、明示的に宣言された変数だけでは無いので注意が必要。複雑な計算をする場合、コンパイラが途中計算用に、メモリを確保する事があり、その分、変数のアドレスが影響を受けます。
さらに、最適化などを行うと、逆に、変数はスタックに確保されず、レジスタだけとか、必要ないと、(内部的に)削除されます。こっちも注意。ただ、アドレスを取ると、必然的に確保されますが。

投稿2020/06/27 06:35

pepperleaf

総合スコア6383

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問