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

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

ただいまの
回答率

89.23%

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

解決済

回答 3

投稿

  • 評価
  • クリップ 1
  • VIEW 522

kamuycikap

score 104

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

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

    unsigned char *mem_tp;
    unsigned char *dbg_tp;
    unsigned char *dbg_tp2;

    unsigned char hoge_rx[15] = {  /* データ格納バッファ */
        0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
    };

    mem_tp = *(unsigned char **)&(hoge_rx[9]); // ★意味がよく分からない他人のコード★
    dbg_tp2 = *(unsigned char *)&(hoge_rx[9]); // mem_tpと同じ結果になるのでは?と思い作ってみた(私が書いた)


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

(gdb) print/x mem_tp
$1 = 0xd0c0b0a
(gdb) print/x dbg_tp2
$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]); でなぜワーニング?

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

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 3

+1

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

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

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/10/16 17:58 編集

    早速の回答ありがとうございます。
    dbg_tp2 = *(unsigned char *)&(hoge_rx[9]);
    を外すとワーニングが出ないのですが、そこがモヤモヤしております。

    おっしゃるように、hoge_rx[9]の中に入っているデータが「アドレス値」であれば、つじつまがあうのかと思うのですが。

    (unsigned Char **)の意味は、

    「ポインタのポインタが指し示すメモリのデータに対してキャスト」

    で理解は合ってますでしょうか?

    キャンセル

  • 2018/10/16 18:02

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

    キャンセル

  • 2018/10/17 12:54 編集

    改めて自分の書き込みを見ましたが、

    「ポインタのポインタが指し示すメモリのデータに対してキャスト」

    これ、日本語がおかしいですね。

    「hoge_rx[9]のアドレスにあるデータを、unsigned char ** としてあつかいますよ」

    と書きたかったです。

    キャンセル

+1

*(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/17 12:51

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

    キャンセル

checkベストアンサー

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/17 12: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と同じものができる。

    ワーニングに関しては、改めて見れば確かに納得です。
    ポインタ変数に実態を入れようとしているわけですから、当然ですね。

    キャンセル

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

  • ただいまの回答率 89.23%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる