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

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

ただいまの
回答率

90.51%

  • C

    4525questions

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

  • Linux

    4436questions

    Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

  • CPU

    52questions

  • バイナリ

    32questions

リトルエンディアンでのデータ配置とメモリアクセス時の処理について

解決済

回答 5

投稿

  • 評価
  • クリップ 0
  • VIEW 184

flyingPengin

score 1

前提

使用環境:仮想環境(VirtualBox)上の64bit KaliLinux(ホストOSは64bitのWindows10)

質問内容

リトルエンディアンでのメモリ上のデータ配置とメモリアクセス時の処理について質問がございます。

下記のプログラムを実行すると

#include <stdio.h>

int main(){
    char *st = "\x41\x42\x43\x44\x45\x46\x47\x48"; 

    for(int i=0;i<8;i++){
        printf("%x  ",st[i]);
    }
    printf("\n");
}
41  42  43  44  45  46  47  48  


がコマンドライン上に出力されます。
この時、メモリ上において文字列stの先頭番地を0x100とします。

次にGDBでこのプログラムをデバックした時に、xコマンドを使って0x100番地以降のメモリ内容を2通り調べました。
1つはコマンド:x/xg 0x100 を入力(つまり0x100番地を先頭に8バイト単位でメモリ内容を表示する)して調べるやり方。
この場合は以下の結果が出力されました。

0x100 :  0x4847464544434241 


これについてはリトルエンディアンでの配置通りなので疑問はないです。

しかし、2つ目の調べ方 コマンド:x/8xb 0x100を入力する(つまり0x100番地を先頭に1バイト単位でメモリ内容を表示する)して調べるやり方で疑問が出ました。
このやり方では以下の結果が出力されました。冒頭プログラムの結果と同様です。

0x100 :  0x41    0x42    0x43    0x44    0x45    0x46    0x47    0x48 


この結果に対して疑問があります。
64bit環境では8バイト単位でリトルエンディアンでメモリにデータが配置されるので、
文字列stのデータがメモリに格納される時、実際のメモリ上のデータ配置は1つめの調べ方の結果のはず。
なので、0x100番地には0x48が配置されている(つまりst[0]=0x48になる)はずなのに、
冒頭のプログラムの結果や2つめの調べ方の結果では0x100番地には0x41が配置されている(つまりst[0]=0x41になる)ことになってしまっています。

以上を踏まえて質問としては
冒頭のプログラムの結果は、本来はリトルエンディアンによる実際のデータ配置を踏まえて

48  47  46  45  44  43  42  41  


になるはずなのに、なぜそうならないのか? です。

まとまりがなくわかりにくい文章で申し訳ございませんが、ご回答いただけると幸いです。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 5

checkベストアンサー

+2

リトル/ビッグの影響は、複数バイトでのアクセスの場合のみです。
char(1byte)の配列では、その順番に格納されます。

char で、0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48 とすると、
この順番にメモリ上に格納されます。(上記の例では、0x100 に 0x41)
これを 8byteのデータ(8byte長のレジスタとして)読みだすと、逆の 0x48474645_44434241 としてレジスタに格納されます。

質問文の例だと、0x100から、8byteを読みだした、という事なので、レジスタには、逆順に格納され、メモリ上とは逆に表示されます。

ただし、今回の例では、0x100 という 8の倍数のアドレスですが、それ以外の場合は要注意です。
また、Big/Little もCPU依存性があり、2byte単位で、交換なんてのもあるので、こちらも要注意。 (Intelは、バイト単位で、入換え)

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/04/13 15:35

    詳細にご回答していただきありがとうございます。

    回答に対して自分なりにまとめました。

    ・冒頭プログラムに関して、まず前提としてプログラム実行開始時に右辺の値の「"\x41\x42\x43\x44\x45\46\47\48"」はメモリ上のテキスト領域にこの順番で配置されている。
    また0x41の値が格納されている番地を0x10番地とする。
    ・冒頭のプログラムの
    char *st = "\x41\x42\x43\x44\x45\46\47\48"の行において、この行の実行時、st[0]に右辺の値を格納する際に、st[0]のデータサイズはchar型の1Byteなので格納順序はまったく関係なくテキスト領域の0x10番地の値(0x41)をst[0]に格納する。次にst[1]に0x11番地の値(0x42)を格納する。以降の値も同様。
    ・なので実際のメモリ上のデータ配置は以下の通り(stの先頭番地を0x100番地とする)
    0x100番地:0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48
    ・GDBのx/xgコマンド(8バイト単位でメモリ内容を表示)実行時に
    コンソール上に「0x100番地:0x484746.....41」が表示されるのは、コマンドを実行してメモリの0x100番地以降の内容を8バイト単位で読み込む際に複数バイトにまたがるメモリアクセスなので、レジスタにはリトルエンディアンの順序に基づいて0x484746.....41が格納される。そして、コンソールにはこのレジスタに格納された値が表示されるから。
    ・プログラムがコンソール上にメモリ内の値を出力する際、メモリ上にアクセスして値をそのままコンソールに出力するのではなく、正確にはメモリ上にアクセスしそこから値をレジスタに格納(複数バイトにまたがるメモリ読み込み時はエンディアンの格納順序が関係する)し、レジスタ内の値をコンソール上に出力する。

    私の認識の齟齬があればそれに対するコメントや追加コメント等がございましたら、ご回答いただけると幸いです。pepperleafさんのご回答が詳細にわたっていてわかりやすかったのでベストアンサーとさせていただきます。

    皆様、ご回答いただきありがとうございました。

    キャンセル

  • 2019/04/13 16:28

    > GDBのx/xgコマンド(8バイト単位でメモリ内容を表示)
    が8バイトの値(int?long?)として表示するのかというのが(ちょっとした検索では)確認できませんでしたが, おそらくそうではないかと推測します.
    であれば,
    ```8バイトをレジスタに転送(この時エンディアンの影響を受ける)→レジスタの8バイトを(上位バイトから)表示```
    となっているものと思います.

    そして,
    > x/8xb 0x100を入力する(つまり0x100番地を先頭に1バイト単位でメモリ内容を表示する)
    では, ```1バイトをレジスタ最下位バイトに転送→レジスタの最下位1バイトを表示, を8回繰り返す``` 動作となり, エンディアンに関係無く先頭アドレスの値から表示されるのではないでしょうか.

    キャンセル

+1

エンディアンが関係するのは複数バイト単位のアクセスとなる, 例えば C の int 等で, 1バイト単位に配置する文字(列)には関係無いということではないでしょうか.

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/04/13 15:37

    ご回答ありがとうございます。
    pepperleafさんと同様の内容のご回答でしたので、pepperleafさんのところにまとめて返答いたしました。

    キャンセル

+1

エンディアンがどうであれ、バイトデータの格納順はアドレスの若い方から順番に格納されます
エンディアンが関わってくるのは、nバイト整数のアクセスのときです。
リトルエンディアンでは逆順にアクセスされますね

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/04/13 15:37

    ご回答ありがとうございます。
    pepperleafさんと同様の内容のご回答でしたので、pepperleafさんのところにまとめて返答いたしました。

    キャンセル

+1

これならひっくり返ってるのが確認できるぞ。

#include <stdio.h>

int main(){
    unsigned long long data = 0x4142434445464748LL;
    const unsigned char* st = (unsigned char*)&data;
    for(int i=0;i<8;i++){
        printf("%x  ",st[i]);
    }
    printf("\n");
    return 0;
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

64bit環境では8バイト単位でリトルエンディアンでメモリにデータが配置されるので、

これが、勘違いの大元ですね。CPUやOSのビット数は関係ありません。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

同じタグがついた質問を見る

  • C

    4525questions

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

  • Linux

    4436questions

    Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

  • CPU

    52questions

  • バイナリ

    32questions