1. ホーム
  2. c

[解決済み] nullポインタを%pで印刷するのは未定義な動作?

2023-02-11 07:42:08

質問

NULL ポインタを表示するのは未定義の動作ですか? %p 変換指定子で NULL ポインタを印刷するのは未定義な動作ですか?

#include <stdio.h>

int main(void) {
    void *p = NULL;

    printf("%p", p);

    return 0;
}

この質問はCの標準に適用されるものであり、Cの実装に適用されるものではありません。

どのように解決するのですか?

これは、英語の限界と規格内の一貫性のない構造に左右される、奇妙なコーナーケースのひとつです。 ですから、せいぜい説得力のある反論ができる程度で、不可能なので を証明する それを :) 1


問題のコードは、よく定義された動作を示します。

として [7.1.4] が質問の基本なので、そこから始めましょう。

以下の各記述は、この後の詳細な説明で明示されていない限り、適用されます。関数への引数が無効な値である場合 ( のような 関数のドメイン外の値、またはプログラムのアドレス空間外のポインタ。 またはヌルポインタ , [... 他の例 ...]. ) [...] の場合、動作は未定義です。 [... 他のステートメント ...].

これは不器用な言語です。 1つの解釈は、個々の説明で上書きされない限り、リストの項目はすべてのライブラリ関数に対してUBであるということです。 しかし、このリストは "such as" で始まっており、網羅的ではなく、例示的であることを示しています。 例えば、文字列の正しいヌルターミネーションについては言及していません (例えば strcpy ).

したがって、7.1.4の意図/範囲は、単に"無効な値"がUBにつながるということであることは明らかです( 特に明記しない限り ). 何が無効な値としてカウントされるかを決定するために、各関数の説明を見る必要があります。

例1 strcpy

[7.21.2.3] はこれだけを書いています。

その strcpy 関数が指す文字列をコピーします。 s2 (終端のヌル文字を含む)を s1 . 重なっているオブジェクト間でコピーが行われた場合、その動作は未定義です。

NULLポインタの明示的な言及はありませんが、NULLターミネータについても言及されていません。 その代わりに、"string pointed to by から推測することができます。 s2 から、有効な値は文字列(すなわち、ヌル終端文字配列へのポインタ)のみであると推測されます。

実際、このパターンは個々の記述を通して見ることができます。他の例もあります。

  • [7.6.4.1 (fenv)]を参照してください。 は、現在の浮動小数点演算環境を オブジェクトに格納します。 envp

  • [7.12.6.4 (flexp)]を参照してください。 に整数を格納します。 オブジェクトに格納します。 exp

  • [7.19.5.1 (fclose)]を参照してください。 ストリームが指す によって stream

例2 printf

[7.19.6.1] には、次のように書かれています。 %p :

p - へのポインタを引数とする。 void . ポインタの値は,実装が定義する方法で,印字文字のシーケンスに変換される。

Nullは有効なポインタ値であり、このセクションはNullが特別なケースであることや、ポインタがオブジェクトを指していなければならないことを明示的に言及することはありません。 したがって、それは定義された動作です。


1. 標準の作者が名乗り出ない限り、あるいは、類似した 根拠 のような、物事を明確にする文書が見つからない限り、です。