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

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

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

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

GCC

GCCはGNU Compiler Collectionの略です。LinuxのC言語コンパイラのデファクトスタンダードであり、数多くの他言語やプラットフォームサポートもします。

Q&A

解決済

1回答

395閲覧

C言語のメモリ上で連続した2つのchar型の位置について

somu

総合スコア32

C

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

GCC

GCCはGNU Compiler Collectionの略です。LinuxのC言語コンパイラのデファクトスタンダードであり、数多くの他言語やプラットフォームサポートもします。

0グッド

0クリップ

投稿2017/08/14 17:16

C言語の以下のコードを実行しました。
このコードは、char型の配列を2つ作り、そのうち後に定義した変数に
大きい数値を入力し、スタックオーバーフローを起こさせてみる、というものです。

環境、コンパイラは ”gcc (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4" です。

#include<stdio.h> #include<string.h> int main(int argc,char *argv[]){ char buffer_one[8], buffer_two[8]; printf("Buffer size : %d\n", sizeof(buffer_one)); int i; for(i=0;i<8;i++) printf("buffer_one[%d] : %p buffer_two[%d] : %p\n", i, &buffer_one[i], i, &buffer_two[i]); putchar('\n'); strcpy(buffer_one,"one"); strcpy(buffer_two,"two"); printf("[前] buffer_two は %p にあり、その値は \'%s\' です\n", buffer_two, buffer_two); printf("[前] buffer_one は %p にあり、その値は \'%s\' です\n", buffer_one, buffer_one); printf("\n[STRCPY] %d バイトを buffer_two にコピーします\n\n", strlen(argv[1])); strcpy(buffer_two, argv[1]); printf("[後] buffer_two は %p にあり、その値は\'%s\' です\n", buffer_two, buffer_two); printf("[後] buffer_one は %p にあり、その値は\'%s\' です\n", buffer_one, buffer_one); }

このプログラムの実行結果は以下です。(スタックの保護は -fno-stack-protector オプションでなくしています)

****@****:~$ ./a.out 12345678901234567890 Buffer size : 8 buffer_one[0] : 0x7fffa6e10730 buffer_two[0] : 0x7fffa6e10720 buffer_one[1] : 0x7fffa6e10731 buffer_two[1] : 0x7fffa6e10721 buffer_one[2] : 0x7fffa6e10732 buffer_two[2] : 0x7fffa6e10722 buffer_one[3] : 0x7fffa6e10733 buffer_two[3] : 0x7fffa6e10723 buffer_one[4] : 0x7fffa6e10734 buffer_two[4] : 0x7fffa6e10724 buffer_one[5] : 0x7fffa6e10735 buffer_two[5] : 0x7fffa6e10725 buffer_one[6] : 0x7fffa6e10736 buffer_two[6] : 0x7fffa6e10726 buffer_one[7] : 0x7fffa6e10737 buffer_two[7] : 0x7fffa6e10727 [前] buffer_two は 0x7fffa6e10720 にあり、その値は 'two' です [前] buffer_one は 0x7fffa6e10730 にあり、その値は 'one' です [STRCPY] 20 バイトを buffer_two にコピーします [後] buffer_two は 0x7fffa6e10720 にあり、その値は'12345678901234567890' です [後] buffer_one は 0x7fffa6e10730 にあり、その値は'7890' です

この結果を見ると、何故か buffer_one と buffer_two の間に
8バイトの間があるのがわかります。
連続して作った変数で、どちらも大きさは8バイトなのになぜこうなるのでしょうか?

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

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

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

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

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

guest

回答1

0

ベストアンサー

コンパイラ次第でしょう・・・
clang 4.0.0ではこうなりました。
Buffer size : 8
buffer_one[0] : 0x7fffffffe798 buffer_two[0] : 0x7fffffffe7a0
buffer_one[1] : 0x7fffffffe799 buffer_two[1] : 0x7fffffffe7a1
buffer_one[2] : 0x7fffffffe79a buffer_two[2] : 0x7fffffffe7a2
buffer_one[3] : 0x7fffffffe79b buffer_two[3] : 0x7fffffffe7a3
buffer_one[4] : 0x7fffffffe79c buffer_two[4] : 0x7fffffffe7a4
buffer_one[5] : 0x7fffffffe79d buffer_two[5] : 0x7fffffffe7a5
buffer_one[6] : 0x7fffffffe79e buffer_two[6] : 0x7fffffffe7a6
buffer_one[7] : 0x7fffffffe79f buffer_two[7] : 0x7fffffffe7a7

[前] buffer_two は 0x7fffffffe7a0 にあり、その値は 'two' です
[前] buffer_one は 0x7fffffffe798 にあり、その値は 'one' です

[STRCPY] 31 バイトを buffer_two にコピーします

[後] buffer_two は 0x7fffffffe7a0 にあり、その値は'0123456789012345678901234567890' です
[後] buffer_one は 0x7fffffffe798 にあり、その値は'one' です
「追記」
アドレスのギャップは8バイトですが、配置されるアドレスが逆転してますね。この状態では、buffer_oneが上書きされる事はありません。

投稿2017/08/14 17:54

編集2017/08/14 18:03
cateye

総合スコア6851

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

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

cateye

2017/08/14 18:07

Cの場合、配列の各要素が連続している事は保証されますが、個々の変数(含む配列)の配置が連続している事は保証されませんd^^
somu

2017/08/14 18:33

回答有難うございます。 では、2つのバッファーはどちらも自動変数で、スタック上に配置されるはずなのに、 2つはつながって配置されず、間に8バイトの空白?があるのは何故なのでしょうか?
somu

2017/08/14 18:35

連投失礼します。 回答者様の結果では空白がありませんね、gccの仕様なのでしょうか
cateye

2017/08/14 18:37 編集

gccでやってみましたd^^ [前] buffer_two は 0x7fffffffe7b0 にあり、その値は 'two' です [前] buffer_one は 0x7fffffffe7a0 にあり、その値は 'one' です [STRCPY] 30 バイトを buffer_two にコピーします [後] buffer_two は 0x7fffffffe7b0 にあり、その値は'012345678901234567890123456789' です [後] buffer_one は 0x7fffffffe7a0 にあり、その値は'one' です gccでは16バイト境界になるみたいですね。(未検証)ただ、ここでもアドレスは逆転しています。 環境:gcc6 (FreeBSD Ports Collection) 6.3.0
somu

2017/08/14 19:09

色々実験してみた所、char型の”配列”は、基本16バイトごとの大きさを取られるようです。 10バイト分確保で実際は16バイト、20バイト分で32バイト確保されるようにです。(公式な確証はありませんが・・・) 協力ありがとうございました。
somu

2017/08/14 19:20

ついでに言うと、(おそらくですが)同一関数内での自動変数は大きさが小さいものが上位に来るように並べ替えられてメモリ上に確保されるみたいです
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問