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

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

ただいまの
回答率

87.94%

関数ポインタの初期化

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 1,269

score 14

関数ポインタの初期化

C言語で、関数ポインタを何も指していない状態で初期化したい場合、

void (*p)(void) = NULL;


としてしまうと、空ポインタ定数 NULL は

JIS X 3010:2003

値0をもつ整数定数式又はその定数式を型void *にキャストした式

とされているため、値0であれば整数型からポインタ型への変換で「処理系定義」となり、void *であれば、void へのポインタから関数型へのポインタ型への変換で「未定義の動作」となりますよね。

どのように初期化する、あるいは何も指していないことを確認するのが正しいのでしょうか。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 2

checkベストアンサー

+1

空ポインタ定数 NULL は JIS X 3010:2003

値0をもつ整数定数式又はその定数式を型void *にキャストした式

とされているため、

いいえ。マクロNULL と 空ポインタ定数(null pointer constant) それぞれの定義を混同ないし誤解釈されているようです。

(§6.3.2.3より引用)
値0をもつ整数定数式又はその定数式を型void *にキャストした式を,空ポインタ定数(null pointer constant)と呼ぶ。
空ポインタ定数をポインタ型に型変換した場合,その結果のポインタを空ポインタ(null pointer)と呼び,いかなるオブジェクト又は関数へのポインタと比較しても等しくないことを保証する。 

(§7.17より引用)
定義するマクロは,NULL及びoffsetofとする。 
  NULL
は,処理系定義の空ポインタ定数に展開する。


void (*p)(void) = NULL;

マクロNULLは「何らかの処理系定義の空ポインタ定数」に展開されますが、少なくともその処理系において「関数ポインタ型変数を合法的に空ポインタ(null pointer)で初期化できる値」であることは保証されます。

おまけ:GNU Cコンパイラ(gcc)では、マクロNULLをリテラル0でも式((void*)0)どちらでもない処理系定義の空ポインタ定数__nullに展開します。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2020/06/12 15:02

    よそのQAサイトですが、標準Cを超える(POSIX)と https://ja.stackoverflow.com/questions/5443/ のような話もあります。

    キャンセル

  • 2020/06/13 10:50 編集

    (1) 定数式 0 や (void *)0 は空ポインタ定数である
    が、他にも処理系定義の空ポインタ定数があることもある

    (2) マクロNULLは、それらのうちのどれか一つを表す

    (3) 整数型からポインタ型への変換は、整数が0であれば問題なく空ポインタとなり、そうでなければ処理系定義の変換
    「オブジェクト型へのポインタ型、不完全型へのポインタ型、void へのポインタ型」から「関数型へのポインタ型」への変換は、元のポインタが空ポインタであれば問題なく空ポインタとなり、そうでなければ未定義の動作

    ということで合っていますか?

    キャンセル

  • 2020/06/14 01:44 編集

    (1), (2) はYESですが、 (3) は誤った解釈と思います。

    C標準が保証するのは「定数式0は空ポインタ定数とも解釈できる」「空ポインタ定数は任意のポインタ型の空ポインタ値と解釈できる」だけです。
    あなたの言う「整数が0であれば問題なく空ポインタとなり」は保証されない、例えば int a = 0; void *p = (void*)a; の振る舞いは処理系定義になると考えます。(式 (void*)a は 定数式0 ではないため)
    オブジェクト型等へのポインタ型 ⇔ 関数ポインタ型 変換でも同じ解釈です。

    キャンセル

  • 2020/06/14 10:25

    定数式0 が必要なわけですね。
    ありがとうございました。

    キャンセル

-1

どのように初期化する、あるいは何も指していないことを確認するのが正しいのでしょうか。

「何も指していない」を表現したいのであれば、0 または NULL を初期値に設定、あるいは代入すれば十分です。

参考: JIS X 3010:2003 6.3.2.3 より

値0をもつ整数定数式又はその定数式を型void *にキャストした式を,空ポインタ定数(null pointer
constant)と呼ぶ。空ポインタ定数をポインタ型に型変換した場合,その結果のポインタを空ポインタ(null pointer)と呼び,いかなるオブジェクト又は関数へのポインタと比較しても等しくないことを保証する。

空ポインタを他のポインタ型に型変換すると,その型の空ポインタを生成する。二つの空ポインタは比較して等しくなければならない。

確認のことを書くのを忘れてました。上にある通り、空ポインタ同士の == による比較は「真」ですので、それで判断できます。
もちろん if ( function_pointer ) のように、ポインタを条件式に指定するだけで ( 自動的に 0 との比較になり、0 から空ポインタが作られて比較対象になるため )、それでも十分です。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2020/06/13 10:57

    なるほど
    バッチリ分かりました!
    ありがとうございました。

    キャンセル

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

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

関連した質問

同じタグがついた質問を見る