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

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

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

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

Q&A

解決済

3回答

1339閲覧

C言語のキャストについて

kamuycikap

総合スコア135

C

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

0グッド

1クリップ

投稿2018/10/16 08:38

■環境
OS    :Windows10
コンパイラ:gcc version 6.3.0 (MinGW.org GCC-6.3.0-1)
デバッガ :GDB
環境   :Emacs24.5で作成/デバッガ起動

他人の書いたコードを読んでいたところ、意味のよく分からないコードに遭遇しました。
キャストのアスタリスクが2つ並んでいます。
下記コードの★部分です。

c

1 unsigned char *mem_tp; 2 unsigned char *dbg_tp; 3 unsigned char *dbg_tp2; 4 5 unsigned char hoge_rx[15] = { /* データ格納バッファ */ 6 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F 7 }; 8 9 mem_tp = *(unsigned char **)&(hoge_rx[9]); // ★意味がよく分からない他人のコード★ 10 dbg_tp2 = *(unsigned char *)&(hoge_rx[9]); // mem_tpと同じ結果になるのでは?と思い作ってみた(私が書いた) 11

上記コードをコンパイルし、gdbで変数の値をダンプしてみた結果が下記の通りです。

gdb

1(gdb) print/x mem_tp 2$1 = 0xd0c0b0a 3(gdb) print/x dbg_tp2 4$2 = 0xa

この部分以降のコードを読むと、mem_tp[0]~mem_tp[14]といった利用を行っています。
正しくは、dbg_tp2のコードではないかと考えたのですが、コンパイルすると、下記のワーニングが発生します。

gcc -g -o testdec.exe testdec.c
testdec.c: In function 'main':
testdec.c:31:13: warning: assignment makes pointer from integer without a cast [-Wint-conversion]
dbg_tp2 = *(unsigned char *)&(check_rx[9]);

ポインターも配列も、全てunsigned charで統一しているのですが、なぜワーニングが出るのかも理解できません。

<理解したいこと>
1.mem_tp = *(unsigned char **)&(hoge_rx[9]); の意味。(キャストで*が2つ)
2.dbg_tp2 = *(unsigned char *)&(check_rx[9]); でなぜワーニング?

書いた人の意図が読み取れずモヤモヤしております。
理解できる方、是非ご教示願います。

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

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

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

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

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

guest

回答3

0

*(unsigned char *)&(check_rx[9])

&(check_rx[9]) → check_rx[9]のアドレス値(Aとする)
(unsigned char *) → (A)のアドレス値をunsigned char型のポインタにキャスト(Bとする)
*→ (B)が指すアドレス位置のデータをunsigned char型の値として取得

ということで、取得されるのはunsigned char型の値になり、dbg_tp2のunsigned char *型と不一致のためワーニングになります。

投稿2018/10/16 09:16

ttyp03

総合スコア16998

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

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

kamuycikap

2018/10/17 03:51

回答有り難うございます。 ポインタ変数に値を入れようとしているわけですね。 理解できました!
guest

0

ポインタのポインタ、ですな。
本来、hoge_rx はポインタの配列だったんでしょう。
そのため、&(hoge_rx[9]) の結果は、hoge_rx[9](ポインタ)の位置のアドレスとなります

しかし、実際のhoge_rx[9] の内容はunsigned char なので、元は整数なのに無理やりポインタにキャストしている、とワーニングが出てます

投稿2018/10/16 08:44

編集2018/10/16 08:46
y_waiwai

総合スコア87749

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

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

kamuycikap

2018/10/17 03:55 編集

早速の回答ありがとうございます。 dbg_tp2 = *(unsigned char *)&(hoge_rx[9]); を外すとワーニングが出ないのですが、そこがモヤモヤしております。 おっしゃるように、hoge_rx[9]の中に入っているデータが「アドレス値」であれば、つじつまがあうのかと思うのですが。 (unsigned Char **)の意味は、 「ポインタのポインタが指し示すメモリのデータに対してキャスト」 で理解は合ってますでしょうか?
y_waiwai

2018/10/16 09:02

そゆことですね。 で、ワーニングはその行で出ているはずです
kamuycikap

2018/10/17 03:55 編集

改めて自分の書き込みを見ましたが、 「ポインタのポインタが指し示すメモリのデータに対してキャスト」 これ、日本語がおかしいですね。 「hoge_rx[9]のアドレスにあるデータを、unsigned char ** としてあつかいますよ」 と書きたかったです。
guest

0

ベストアンサー

1.mem_tp = *(unsigned char **)&(hoge_rx[9]); の意味。(キャストで*が2つ)

1.1 hoge_rx[9] --> hoge_rx の9番目 (10番目と言った方が正しい?)のデータ
1.2 &hoge_rx[9] --> hoge_rx[9] のアドレス --> unsigned charなので、(hoge_rx + 9) ... 型は、(unsigned char *)
1.3 (unsigned char **)&(hoge_rx[9]) --> キャストしているので、 unsigned char のポインタのポインタとなります。
1.4 *(unsigned char **)&(hoge_rx[9]) --> 1.3 のポインタが示す先となります。 --> unsigned char へのポインタとなります。(unsigned char *)
unsigned char *mem_tp なので、型は一致します。(従ってエラー/ワーニングとならない)
ただし、mem_tpが実際に示すものは、hoge_rx[9] なので、hoge_ex[9] から、 4byte(64bitなら、8byte)が、unsigned charへのポインタと見なされます。

2.dbg_tp2 = *(unsigned char *)&(check_rx[9]); でなぜワーニング?

(ttyp03さんと、ほぼ同じですが)
2.1 &(check_rx[9]) --> ここまでは、上記と一緒。(unsigned char*)
2.2 (unsigned char *)&(check_rx[9]) --> (unsigned char *)としてキャスト
2.3 *(unsigned char *)&(check_rx[9]) --> * が付くので、型は、 unsigned char
2.4 unsigned char *dbg_tp2; から、 dbg_tp2 は、unsigned charへのポインタだが、= の右側は、 unsigned char で型が違うので、ワーニングとなります。

投稿2018/10/16 10:44

pepperleaf

総合スコア6383

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

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

kamuycikap

2018/10/17 03:50 編集

回答有り難うございます。 腑に落ちました。 下記のコードと同等と理解できました。 unsigned char **check_pp; /* ポインタのポインタ宣言 */ unsigned char *data_p; /* ポインタ宣言 */ data_p = &hoge_rx[9]; check_pp = (unsigned char **)data_p;  // 今回わからなかったキャスト dbg_tp = *(check_pp);           // このように書くとmem_tpと同じものができる。 ワーニングに関しては、改めて見れば確かに納得です。 ポインタ変数に実態を入れようとしているわけですから、当然ですね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問