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

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

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

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

ポインタ

ポインタはアドレスを用いてメモリに格納された値を"参照する"変数です。

関数

関数(ファンクション・メソッド・サブルーチンとも呼ばれる)は、はプログラムのコードの一部であり、ある特定のタスクを処理するように設計されたものです。

Q&A

解決済

2回答

4055閲覧

関数ポインタの初期化

tails

総合スコア22

C

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

ポインタ

ポインタはアドレスを用いてメモリに格納された値を"参照する"変数です。

関数

関数(ファンクション・メソッド・サブルーチンとも呼ばれる)は、はプログラムのコードの一部であり、ある特定のタスクを処理するように設計されたものです。

0グッド

0クリップ

投稿2020/06/12 04:31

関数ポインタの初期化

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

C

1void (*p)(void) = NULL;

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

JIS X 3010:2003

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

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

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

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

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

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

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

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

guest

回答2

0

ベストアンサー

空ポインタ定数 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
は,処理系定義の空ポインタ定数に展開する。


c

1void (*p)(void) = NULL;

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

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

投稿2020/06/12 05:49

編集2020/06/12 05:58
yohhoy

総合スコア6191

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

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

tails

2020/06/13 02:27 編集

(1) 定数式 0 や (void *)0 は空ポインタ定数である が、他にも処理系定義の空ポインタ定数があることもある (2) マクロNULLは、それらのうちのどれか一つを表す (3) 整数型からポインタ型への変換は、整数が0であれば問題なく空ポインタとなり、そうでなければ処理系定義の変換 「オブジェクト型へのポインタ型、不完全型へのポインタ型、void へのポインタ型」から「関数型へのポインタ型」への変換は、元のポインタが空ポインタであれば問題なく空ポインタとなり、そうでなければ未定義の動作 ということで合っていますか?
yohhoy

2020/06/13 16:48 編集

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

2020/06/14 01:25

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

0

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

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

参考: JIS X 3010:2003 6.3.2.3 より

値0をもつ整数定数式又はその定数式を型void *にキャストした式を,空ポインタ定数(null pointer

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

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

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

投稿2020/06/12 05:06

編集2020/06/12 05:24
angel_p_57

総合スコア1672

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

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

tails

2020/06/13 01:57

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問