掲示板利用宣言

 次のフォームをすべてチェックしてからご利用ください。

 私は

 題名と投稿者名は具体的に書きます。
 課題の丸投げはしません。
 ソースの添付は「HTML変換ツール」で字下げします。
 返信の引用は最小限にします。
 環境(OSとコンパイラ)や症状は具体的に詳しく書きます。
 返信の付いた投稿は削除しません。
 マルチポスト(多重投稿)はしません。

掲示板2

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧

No.30296

void ** に関して
投稿者---h3X(2007/06/13 00:38:31)


C言語の規格におきまして,汎用ポインタ(void *)へのポインタ(void **)は
規定されているのでしょうか?

K&R 第2版 の p146 に

void qsort(void *v[], int left, int right, 略)

と,第1引数が汎用ポインタへのポインタとして宣言されていました.

ご教授よろしくお願い致します.


この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:void ** に関して 30297 たかぎ 2007/06/13 01:04:15
<子記事> Re:void ** に関して 30298 yoh2 2007/06/13 01:11:15


No.30297

Re:void ** に関して
投稿者---たかぎ(2007/06/13 01:04:15)
http://takagi.in/


規定されています。
ただし、そのものズバリではなく、もっと汎用性の高い規定になっています。要約すると、

・ポインタ型は、関数型・オブジェクト型・不完全型から派生することができる。
・ポインタ型はオブジェクト型である。
・派生によってポインタ型を作ることを再帰的に行うことができる。

といったところです。
void型は不完全型の一種ですので、それから派生してvoidへのポインタ型を作ることができます。voidへのポインタ型はオブジェクト型の一種ですので、それから派生してvoidへのポインタ型へのポインタ型を作ることができます。



この投稿にコメントする

削除パスワード

No.30299

Re:void ** に関して
投稿者---h3X(2007/06/13 01:16:35)


高木樣,早速のご返事ありごとうございます.

高木樣にご教授頂いた内容は理解いたしました.

以下のリンク「C FAQ 4」に掲載されている内容について,再び質問したいのですが,

http://www.kouno.jp/home/c_faq/c4.html#0

-- 以下引用4.9: ----------------------------------------------------

参照呼び出しに使うため汎用のポインターを関数に渡すのに、 void **を使うことができるか。

A:
移植性まで考れば不可能である。C言語には汎用のポインターへのポ インター型は存在しない。
void *が汎用のポインターとして振る舞う のは、他の型のポインターをvoid *に設定したり参照するときに、
自 動的に変換が行われるからである。void *以外の何かを指している void **を使って間接参照しようとすると、
この変換は実行できない (隠れた正しいポインターの型がわからない)。
---------------------------------------------------------------------

上記記述に置きまして,「C言語には汎用のポインターへのポ インター型は存在しない。」という記述が気になっております.

私の理解不足ですが,ご教授よろしくお願い致します.



この投稿にコメントする

削除パスワード

No.30301

Re:void ** に関して
投稿者---yoh2(2007/06/13 01:31:19)


>上記記述に置きまして,「C言語には汎用のポインターへのポ インター型は存在しない。」という記述が気になっております.

汎用の(ポインターへのポインター)が存在しないのであって、(汎用のポインター)へのポインターは存在します。
原文(和訳に較べてかなり長いです。和訳後に追記されたのかも)を見れば分かると思います。
http://c-faq.com/ptrs/genericpp.html

# 実は同じことをこの掲示板に書いたことがあったのですが、ここ、流れると検索しにくいので再掲しました。


この投稿にコメントする

削除パスワード

No.30302

Re:void ** に関して
投稿者---h3X(2007/06/13 01:46:12)


>汎用の(ポインターへのポインター)が存在しないのであって、(汎用のポインター)へのポインターは存在します。

なるほど!大変よく分りました.
これで疑問が1つ解決致しました.

ありがとうございます.

(後,No.30300の疑問が解決すればハッピーです)



この投稿にコメントする

削除パスワード

No.30303

Re:void ** に関して
投稿者---yoh2(2007/06/13 01:54:33)


>(後,No.30300の疑問が解決すればハッピーです)

どっちの枝に続けるか迷ったけど、流れができているこっちで。

> qsort((void **)lineptr, 0, nlines-1, 略)

これ、まんま C FAQ 4.9 (URLは前レス参照) の
|        void f(void **);
|        double *dp;
|        f((void **)&dp);

このパターンですので、C FAQにある通り、移植性はありません。事実上動く場合は多いのですが。


この投稿にコメントする

削除パスワード

No.30304

Re:void ** に関して
投稿者---h3X(2007/06/13 02:09:07)


>このパターンですので、C FAQにある通り、移植性はありません。事実上動く場合は多いのですが。

「void *以外の何かを指している void **を使って間接参照しようとすると、この変換は実行できない (隠れた正しいポインターの型がわからない)。」

とC FAQ にありますが,
#include <stdio.h>

int main(int argc, char **argv)
{
    int a = 5;
    int *p = &a;
    void **vp = &p;

    printf("%d\n", **(int **)vp);

    return 0;
}

のように,ちゃんとキャストしてから間接参照すれば,コンパイル時に

try.c:7: 警告: 互換性のないポインタ型からの初期化です

のような警告がでますが,ちゃんと「5」と表示され,私の感覚ではどこに問題があるのだろう?となります.

例えば,どういった環境があるために移植性がないと C FAQ では言っているのかが分れば,納得できると思います.

(英語サイトの方にもしかしたら書いてあるのかもしれませんが,辞書を
引きながらの訳では,いまひとつ理解できないもので...)

度重なる質問申訳ございませんが,ご教授よろしくお願い致します.



この投稿にコメントする

削除パスワード

No.30305

Re:void ** に関して
投稿者---yoh2(2007/06/13 03:40:09)


>(英語サイトの方にもしかしたら書いてあるのかもしれませんが,辞書を
>引きながらの訳では,いまひとつ理解できないもので...)

そんなこと言わずに頑張って読んでみて下さい。C FAQ 4.9の原文は、和訳と比べ物にならない
くらいの情報量がありますので。

> 例えば,どういった環境があるために移植性がないと C FAQ では言っているのかが分れば,納得できると思います.

これについてもきちんと書かれています。
とはいえ、文章で説明されているだけなので、例示コードと共にちょっとまとめてみます。

1. void *と任意の型Tへのポインタの変換では、何かしらの内部表現の変換を行う場合がある。
この辺はC FAQ 5.17 (http://www.kouno.jp/home/c_faq/c5.html#17) も参照。

2. もし、T * <-> void * 間で内部表現の変換が必要な場合、以下のコードで問題発生。
    T **ppt;
    ...
    /* void ** は汎用ポインタではないので、内部表現の変換などといった器用な真似はしない。
     * なお、別の理由により、厳密にはこの部分で早くも未定義の挙動を起こす可能性があるけど割愛。
     * (Cの規格書か、かなり詳しい書籍を調べてみましょう。K&R第2版には載っていなかったかも)
     */
    void **ppv = (void **)ppt;
    void *pv = *ppv;

    /* void * → T * なので内部表現変換。
     * ……ちょっと待った。T * → void * の変換が行われていないのに (pvの内部表現が T * のまま)
     * void * → T * 変換なんかされたらポインタが壊れてしまう。
     */
    T *pt = (T *)pv;



この投稿にコメントする

削除パスワード

No.30306

Re:void ** に関して
投稿者---yoh2(2007/06/13 22:36:15)


補足。
ここまで長々と書かなくても、
    void *pv = *ppv;

T ** の内部表現とvoid ** の内部表現が違っていればこの時点でアウトですね。


この投稿にコメントする

削除パスワード

No.30307

Re:void ** に関して (解決致しました)
投稿者---h3X(2007/06/14 02:08:20)


マシンによってはポインタサイズが4バイトではなく2バイト等などに
なるのは知っていましたが,同一マシン内においても,

異ったポインタタイプには,異った「ポインタサイズ」や,異った「ポインタ
表現」が現在でも可能性としては存在しうるという事実は新鮮でした.

(Again, the discussion so far assumes that different pointer types
might have different sizes or representations, which is rare today,
but not unheard of.)

ご丁寧なご説明ありがとうございました.
(精進いたします)


この投稿にコメントする

削除パスワード

No.30298

Re:void ** に関して
投稿者---yoh2(2007/06/13 01:11:15)


>C言語の規格におきまして,汎用ポインタ(void *)へのポインタ(void **)は
>規定されているのでしょうか?

結論から言うとyes。
規定されている、というより、禁止されていない、といった方がより正確だと思います。
void ** は、int * や int ** 、struct hoge * 等と同様に、ある型を指すポインタであり、
それ以上でもそれ以下でもありません。
ただ、「ある型」というのが、void * というちょっと変わった型である、というだけです。

なお、void ** は、あくまで「汎用のポインタ」を専門に指すポインタであって、
void ** 自体は汎用でないことに注意して下さい。
例:
   int n, *pn;
   void *pv = &n;      /* OK: pは汎用ポインタだから int * を格納できる */
   void **ppv1 = &pv;  /* OK: &pvは void ** 型 */
   void **ppv2 = &pn;  /* NG: void ** 自体は汎用ではないので int ** は代入不可 */

# まあ、代入不可といっても、Cの場合、警告が出る程度でコンパイルは通ってしまいますが。


この投稿にコメントする

削除パスワード

No.30300

Re:void ** に関して
投稿者---h3X(2007/06/13 01:27:15)


ご返事ありがとうございます.

>void **ppv2 = &pn; /* NG: void ** 自体は汎用ではないので int ** は代入不可
># まあ、代入不可といっても、Cの場合、警告が出る程度でコンパイルは通ってしまいますが。

K&R 第2版 p146 におきましても

void qsort(void *v[], int left, int right, 略)

という qsort の自作関数を

char *lineptr[MAXLINES];

qsort((void **)lineptr, 0, nlines-1, 略)

と,第1引数を強引?にキャストしています.

これは問題のない,移植性のあるやり方なのでしょうか?



この投稿にコメントする

削除パスワード

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧