🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C

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

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

Q&A

解決済

3回答

3630閲覧

デバッグモードでのメモリ内容の表示についての疑問

mery

総合スコア27

C

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

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

0グッド

0クリップ

投稿2019/11/10 08:26

編集2019/11/10 09:57

前提・実現したいこと

windowsのメモ帳で作成したファイル(ユニコード ビッグエンディアンで保存)を開いて表示するプログラムを作り、デバッグをしていたのですが、デバッグ中のメモリ内容の表示について疑問があります。

読み込んだ文字列はLPTSTR lpUniText;で宣言した変数に保存してあります。
ファイルの内容が「テスト」という文字列の場合lpUniTextが指すアドレスを調べると、メモリウィンドウにはFE FF 30 C6 30 b9 30 C8 00 00というデータが表示されました。
しかしソースコード中のlpUniText[1]という部分を選択してマウスカーソルをそこに移動するとそこには0xc630という値が表示されました。
ビッグエンディアンは上位バイトからメモリに並べるはずなのでどちらの表示もlpUniText[1]のデータは30 C6になると思うのですがどうしてこの2つの表示は異なるのでしょうか?

イメージ説明

補足情報(FW/ツールのバージョンなど)

Microsoft Visual C++ 2010 Express C言語
WIN32 ユニコードビルド Windows7

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

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

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

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

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

guest

回答3

0

ベストアンサー

メモリウインドウは、メモリの格納状態をそのまま表示します。メモリイメージそのままですので、エンディアンの変換も行われません。

変数(今回はlpUniText[1])にカーソルを当てた時は、その変数の「値」を表示しますが、この時はメモリから読み込んでエンディアンの変換をして、正しい値にしてから表示してくれます。このおかげで、変数にカーソル当てて中身を確認する時にメモリの格納方法(リトルエンディアンになっていること)を気にしないで済みます。

たとえばint a = 1;としてaにカーソル当てると1と表示されるかと思います。この時にメモリウインドウで&aを調べると01 00 00 00とリトルエンディアンで格納されているのが確認できるかと思います。

投稿2019/11/10 11:56

segavvy

総合スコア1038

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

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

mery

2019/11/11 10:28

回答ありがとうございました。 「メモリから読み込んでエンディアンの変換をして、正しい値にしてから」という部分の正しい値とはどういう意味なのでしょうか? 同じファイルをリトルエンディアンで保存し読み込んでみるとメモリウィンドウにはff fe c6 30 b9 30 c8 30 00 00が表示されソース中のlpUniText[1]にカーソルを当てると0x30c6が表示されます。 「テ」の文字コード0x30c6 をリトルエンディアンでメモリに読み込むと0xc630という値が、ビックエンディアンで読み込むと0x30c6という値がメモリウィンドウに表示されているわけですから正しい値とは「テ」の文字コード0x30c6 ではないのですか?
segavvy

2019/11/11 15:07

「メモリから読み込んでエンディアンの変換をして、正しい値にしてから」と書きましたが、正しくは「メモリから読み込んで、それをリトルエンディアンと見なして変換してから」の誤りでした。訂正します。 メモリへの格納の方式がビッグエンディアンなのかリトルエンディアンなのかは、プラットフォームで決まります。お使いのWindowsはリトルエンディアンで、これをプログラムで切り替えることはできません。メモリに格納されたデータは、常にリトルエンディアンと見なして処理されます。 ReadFileにはエンディアンを変換する機能はなく、そのままメモリ上に読み込みます。リトルエンディアンで保存されているファイルは、そのままリトルエンディアンでメモリに読み込まれ、お使いのWindowsはメモリに格納されたデータをリトルエンディアンとして処理するので、問題なく処理できます。変数にマウスカーソルを当てても正しい値が表示されます。 ビッグエンディアンのファイルの場合でも、ReadFileはそのままメモリに読み込んでしまいます。お使いのWindowsはそれをリトルエンディアンだと思って処理してしまうので、カーソルを当てても正しい値が表示されないのです。 ReadFileにはエンディアンを変換する機能はありません。また、お使いのWindowsはメモリ上のデータを常にリトルエンディアンとみなして処理します。ユニコードがどちらのエンディアンで保存されていても、この動作は変わりません。エンディアンが合わない場合は、プログラムで変換してあげないと正しく文字を解釈できないことになります。
mery

2019/11/12 09:48

回答ありがとうございます。やっと理解できました。
guest

0

プロジェクトの文字コードが Unicode であれば、LPTSTRwchar_t * なので、メモリに 0xfe 0xff 0x30 0xc6 と読み込まれていれば、lpUniText[1]は 0xc630 になります。
読み込んだデータがビックエンディアンでも Windows マシンの CPU は リトルエンディアンなので、デバッガーではそのように表示されますね。
「テ」はUTF-16では 0x30c6 ですが、これをメモリーに格納すると、リトルエンディアンの CPU では 0xc6 0x30 となります。メモリに 0x30 0xc6 と格納されていれば、0xc630 という文字になります。

デバッガはメモリに読み込まれているデータがビッグエンディアンなんてことはわかりませんから、全てリトルエンディアンのデータとして扱います。

C言語の標準関数ではありませんが、VC ならば _byteswap_ushort関数を使えばバイトスワップができます。

投稿2019/11/10 11:25

編集2019/11/10 11:37
Bull

総合スコア986

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

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

mery

2019/11/11 11:05

回答ありがとうございます。 「デバッガはメモリに読み込まれているデータをすべてリトルエンディアンのデータとして扱う」ということはつまり、 ビッグエンディアンで保存された値を読み込んだ場合は「テ」の文字コード0x30c6は上位バイトからメモリに読み込まれメモリウィンドウには30 c6の順に格納される。 リトルエンディアンで保存された値を読み込んだ場合は「テ」の文字コード0x30c6は下位バイトからメモリに読み込まれメモリウィンドウにはc6 30の順に格納される。 どちらの場合もメモリウィンドウに表示されているデータは上位バイトと下位バイトが逆になっているとデバッガは判断し、そのデータの上位バイトと下位バイトを入れ替え元に戻す。 だからlpUniText[1]にカーソルを当てた時はメモリの値の上位バイトと下位バイトが入れ替わった値が表示される。 ということでいいのでしょうか?
Bull

2019/11/11 12:06 編集

ファイルをどのように読み込んでいるのかはわかりませんが、メモリに 0xfe 0xff 0x30 0xc6 と読み込まれている前提で回答しました。 メモリウィンドウに表示されるのは何の加工もしない、生の(Raw)データですね。指定されたアドレスから、16進数で表示しているだけです。エンディアンは関係ないですね。 一方 lpUniText は wchar_t * なので、デバッガは上位バイトと下位バイトを入れ替えて表示しているように見えます。 Visual Studio のデバッガは、リトルエンディアンだからといって、特段変換して表示や変更などしているわけではないと思います。wchar_t は 2byte のデータなので、上位バイトと下位バイトが反転してメモリに格納されているように見えます。見えますというと変に思えますが、リトルエンディアンの CPU ではこれが自然な状態です。 プログラムで例えば wchar_t w = 0x30c6; とした場合、メモリには 0xc6 0x30 と格納されます。 デバッガがそのアドレスからデータを読み込んだら、それは 0x30c6 でしょう。それをそのまま表示しているだけだと思います。
mery

2019/11/11 13:30

ファイルはCreateFile関数で開き、ReadFile関数で普通に読み込んでいます。 ビッグエンディアンの意味を調べると「2バイト以上で構成されるデータをメモリーに格納するときの方式」と書いてあったので、テキストファイルのデータをプログラムのメモリに読み込むときにテキストファイルのデータを上位バイトから順にメモリに格納していると思っていましたがそれは違うのですね? テキストファイルを保存するときにビッグエンディアンを選択した場合は、文字コードを上位バイトから記録したファイルが作成され、そのファイルをプログラムで読み込むときはそのデータをそのままメモリに読み込んでいるわけですか。
Bull

2019/11/11 13:45

そうですね、メモリの状態からみても、テキストファイルをそのまま読んでいるようです。
guest

0

FE FFというのはBOMというものです。
バイトオーダーマーク

んで、ビッグだろうがリトルだろうが16ビット整数で表すと0xc630になるのは変わりません


あ、勘違い
たんにメモリウィンドウのカーソル表示がデフォルトのリトルになってるだけでは
メモリ上に展開されてるバイトパターンがビッグかリトルかはそれだけ見ててもわかりませんから。

投稿2019/11/10 08:30

編集2019/11/10 08:39
y_waiwai

総合スコア88038

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

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

mery

2019/11/10 08:44

回答ありがとうございます。 そのメモリウィンドウのカーソル表示というのはどこで変更できるのですか?
y_waiwai

2019/11/10 08:49

ビッグエンディアン表示に変更するということですか。 ちょっとぐぐってみましたが、そういう設定ができるという情報はでてこないですねえ。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問