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

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

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

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

Q&A

解決済

6回答

17478閲覧

ポインタに直接アドレスを入れて、中身を見る!

strike1217

総合スコア651

C

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

0グッド

0クリップ

投稿2016/11/30 11:22

以前から、こんなことってできるのかな?
と思っていたことがあります。

例えば、「とある変数のアドレスが分かっていた」という前提で進めます。
ex: とある変数i = 0xffff436e だったとします。
ASLRは無効の状態で考えてください。

int main(){
char *g = "\x6e\x43\xff\xff";
printf("%d", *g);
return 0;
}

とすると、、、110という結果が出てきました。

この110という数字はとある変数iの値であると”必ず”言えますか?

gの変数はダブルクォーテーションでくくっているので、文字列であると思います。
そうすると....
「"\x6e\x43\xff\xff"の文字列の先頭のアドレスに格納されている値を%dで出力しているだけ」という結論になりそうです。

自分的にはiの値ではないような気がしています。
どなたか教えてください。

一応はしてみたのですが・・・・『??』状態になってます。

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

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

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

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

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

guest

回答6

0

現代的なOS上でのプログラミングで出てくる場面はほぼないですが、ハードウェア寄りの開発では、「特定のメモリアドレスを読む/書く」ことが必要となる場面もあります。

C

1//PC-98のVRAMを直接叩く例 2 3#define PLANE1 ((unsigned char *)0xa8000000L) 4#define PLANE2 ((unsigned char *)0xb0000000L) 5#define PLANE3 ((unsigned char *)0xb8000000L) 6 7// あとからPLANE1[100] = 8; のように書き込む

投稿2016/11/30 22:56

maisumakun

総合スコア145183

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

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

Y.H.

2016/12/01 00:18

GPIOボードでメモリマップドI/Oとかまだまだ現役なのかな? raspberry piでメモリマップドI/O叩いて外部端子に繋いだ機器を制御とか。
strike1217

2016/12/01 07:01

ありがとうございます。
guest

0

###一つのメモリ領域を複数の型として処理する共用体の紹介

C言語の言語仕様内でまっとうに(?)解決する方法として共用体(union)があります。

C

1#include <stdio.h> 2union uniondata { 3 char g[5]; 4 unsigned int i; 5}; 6 7int main(){ 8 union uniondata udata; 9 10 strcpy(udata.g, "\x6e\x43\xff\xff"); 11 12 printf("g = %s\n", udata.g); 13 printf("i = %08x\n", udata.i); 14 15 return 0; 16}

union使ったコードなんて20年以上ぶりに書いたんで合ってるかちょっと心配 :-(

投稿2016/11/30 15:01

Y.H.

総合スコア7914

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

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

strike1217

2016/11/30 15:53

試してみますね! ありがとうございます。
guest

0

えーと、まず、次のコードですが、

char *g = "\x6e\x43\xff\xff";

ですが、文字型のアドレスを格納する変数 g に、
文字列次のデータが格納されたメモリの先頭アドレスを代入しています。

addr : +0 +1 +2 +3 +4
xxxx : 6E 43 FF FF 00

ここで、アドレスを xxxx と書いたのは、この場合、文字列のアドレスは、
リンク時に決定されるアドレスだからです。
で、

printf("%d", *g);

は、先頭にある 6e (16進数)というデータを数字(10進数)で表示しなさいと
いう事になるので、結果として、110 という値が表示されます。

しかし、質問に、 ex: とある変数i = 0xffff436e だったとします。
とありますので、やりたい事とコードが違っている様に思えます。
多分やりたい事は、

char *g = (char *)0xFFFF436E;

を行った場合という事ではないでしょうか?
組み込みの環境などで、物理メモリの 0xFFFF436E を直接アクセス
する必要がある場合には、実際にこのような書き方をする場合もあります。

一般的な、WindowsやLinuxのアプリケーションでは、このような事をやっても、
おそらくアクセス違反となるでしょう。

投稿2016/11/30 12:51

ShinyaAnan

総合スコア241

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

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

strike1217

2016/11/30 14:20

確かにSegmentation faultになってしまいますね。 仮想メモリ空間に配置されているアドレスであれば、これでできないかな〜〜 と思ったのですが・・・
guest

0

ベストアンサー

もしかして、やりたかったのはこういうこと?

C

1#include <stdio.h> 2int main(){ 3 char *g = "\x6e\x43\xff\xff"; 4 printf("%08x\n", *(unsigned int *)g); //==> ffff436e 5 return 0; 6}

投稿2016/11/30 12:41

編集2016/11/30 12:47
YsMana

総合スコア257

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

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

strike1217

2016/11/30 14:23

できましたああ!! ありがとうございます。 少しだけ違いますが、あなたのソースコードを元に作り直してみたら、Segmentaion faultにならなかったですう!
otn

2016/11/30 15:37

これだと、「とある変数のアドレスが分かっていた」とは何の関係もありませんけど。
strike1217

2016/11/30 15:56 編集

char *g = "\x6e\x43\xff\xff"; このようにして、文字列をintのポインタにキャストすると 0xfff436efのアドレスにある”とある変数の中身”を%dなどを使って表示させることができます。
strike1217

2016/11/30 15:58

char *g = 0xffff436e; printf("%d", *g); otnさんのと融合すると、多分こうですかね。 char *g = "0xffff436e"; printf("%d", *(unsigned int *)g);
strike1217

2016/11/30 16:05 編集

キャストしている点が異なるようです。 リトルエンディアン表記でも可能だと思うんですが、試してみます。
strike1217

2016/11/30 16:09

リトルエンディアンだとむしろダメでした。 char *g = "\x6e\x43\xff\xff"; → char *g = "0xffff436e"; これが正しいですね!
YsMana

2016/11/30 18:10

> char *g = "\x6e\x43\xff\xff"; > このようにして、文字列をintのポインタにキャストすると > 0xfff436efのアドレスにある”とある変数の中身”を%dなどを使って表示させることができます。 それは誤解ですね。 私の書いたコードはアドレス0xfff436efなんて参照してなくて、 0xfff436efはポインタgが参照している先にあるデータでしかありません。 参照先のアドレスは  printf("%p\n", g); で表示されるアドレスです。 本当に0xfff436efにある(例えばunsigned int型の)データを参照したいのなら  unsigned int *g = 0xfff436ef;  printf("%08x\n", *g); となります。 しかし、他の回答のコメントでやりとりされているとおり でたらめなアドレスにアクセスしたってたいていはsegmentation faultになるでしょう。 やるなら、質問文に書かれている通り、「とある変数のアドレス」のように確実にアクセス可能なアドレスにしましょう。 > char *g = "0xffff436e"; これは"0xffff436e"という文字列の格納先を指しているポインタを作っているだけで、 アドレス0xfff436efにアクセスするという趣旨からどんどんかけ離れていってますよ?
ikedas

2016/12/01 04:06

たとえばlong intとポインタ型が同じサイズだったとして、 int i = 110; long p; p = (long)&i; printf("%d", *(int *)p); 110が出力されます。何事の不思議なけれど。
strike1217

2016/12/01 07:01

自分の実験は char *g = "0xffff436e"; printf("%d", *(unsigned int *)g); これで0xffff436eのアドレス内にある値を見ることができましたが・・・
ikedas

2016/12/01 07:13

いや、文字列の中で「0x」とかおかしいんで……。
otn

2016/12/01 08:28

> これで0xffff436eのアドレス内にある値を見ることができましたが・・・ それは単なる勘違いです。
strike1217

2016/12/01 13:49

え? そうなんですか? int i = 200; で%dの結果は200になったんですが・・・
strike1217

2016/12/01 13:52

あ、ごめんなさい。 書き方にミスがありました。 char *g = "0xffff436e"; → char *g = 0xffff436e; 文字列ではありませんでした。すいません。
strike1217

2016/12/01 13:55

char *g = 0xffff436e; printf("%d", *(unsigned int *)g); このようにして、成功したんですが・・・・
ikedas

2016/12/01 14:02

ご質問への回答は「できます」で間違いないんです。しかし、今のあなたのやり方では効率が悪すぎるし、得られる結果も不確かすぎます。 デバッガの使い方を調べてみるといいと思います。メモリのどこに何があるか直接見れます。
otn

2016/12/01 14:25

> このようにして、成功したんですが・・・・ それは正しいです。文字列と数値は全く違うものです。
strike1217

2016/12/01 14:38

書き方間違えてましたね。 お手数をおかけしました。 すいません。
guest

0

gは、charへのポインタなので、*gはcharです。gは文字列の先頭アドレスが入っているので、*gはその先頭文字、つまり'\x6e'です。
つまり、

C

1printf("%d", '\x6e');

とおなじで、100が表示されます。

とあるchar変数のアドレスが0xffff436eだったとして、その変数の値を表示したいのなら、

C

1char *g = 0xffff436e; 2printf("%d", *g);

です。

投稿2016/11/30 12:38

otn

総合スコア84487

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

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

strike1217

2016/11/30 14:24

ん〜〜 segmentation faultになってしまいます
otn

2016/11/30 14:43

> segmentation faultになってしまいます そりゃ、割り当てられた以外のメモリをアクセスするとそうなります。 あくまで、 > とあるchar変数のアドレスが0xffff436eだったとして、 が前提です。ちゃんと割り当てメモリ内のアドレスを指定してください。
guest

0

回答ではありません。すみません。

「"\x6e\x43\xff\xff"の文字列の先頭のアドレスに格納されている値

って具体的に何を指しているのでしょうか?

ex: とある変数i = 0xffff436e だったとします。

この仮定が及ばない(変数iがない)と思われる以下の環境でも110と出力されるようですが、どう思われますか?
hogehuga

投稿2016/11/30 12:28

編集2016/11/30 12:30
can110

総合スコア38252

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

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

strike1217

2016/11/30 14:18

int('0x6e', 16) ==> 110 となるので、16進数0x6e は%dの10進数で表現すると110になります。 \x6eは先頭にありますよね。
strike1217

2016/11/30 14:29

あ、ちなみに「ポインタは先頭のアドレスを示す」ということはご存知かと思います。
can110

2016/11/30 15:22

ん。だから提示されたコードではそもそも"\x6e~"の"~"以降はなんでもいいわけで、iうんぬんの記述も無意味なのがこちらのいいたかったことだとご理解いただければよいです。
strike1217

2016/11/30 16:03

あ、そういうことですね。 確かに質問内のプログラムではiの変数がなんであろうが関係ないことになってしまいますね
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

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

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

質問する

関連した質問