16

Cを使用NULLすると、任意のnullポインター定数、つまり、0と評価される任意の整数定数式、またはにキャストされるそのような式を定義できますvoid *。私の質問は、定義の選択が本当に重要かどうか、つまり、そうでなければ正しいプログラムがどの定義が使用されているかに依存するかどうかに関するものです。NULLこの質問では、可変個引数関数やプロトタイプがない関数に渡されるなどの問題は、すでに個別に扱っているので無視したいと思います。と仮定sizeof NULL == sizeof(void *)sizeof NULL == sizeof(T)て、ある整数型については、ポインタ型があるかどうかの質問に答えるには十分Tではありません。sizeofNULL

明らかに、C11は、キーワードのタイプNULLまたはその他の式を区別する方法を提供します。_Generic

C99はまた、信頼できると思われる1つのあいまいな方法を提供します。

int null_has_ptr_type()
{
    char s[1][1+(int)NULL];
    int i = 0;
    return sizeof s[i++], i;
}

NULL準拠するCプログラムによってタイプを判別できる他の方法はありますか?C89で機能するものはありますか?

4

4 に答える 4

6

質問、回答、コメントを通じて、次のことを確立したと思います。

  1. C11 の方法は簡単です ( _Generic)。
  2. C99 の方法は、コンパイラにバグがあるため、かなり信頼できません。
  3. 文字列化のアプローチは、typedef.
  4. 他のアプローチは見つかりませんでした。

したがって、信頼できるC11以前の方法はなく、有効なC99以前の方法はないようです。

于 2013-06-19T10:20:24.420 に答える
4

NULLの文字列定義を取得してから、必要に応じて完全なチェックを実行します。これは非常に単純な心のあるものです:

#define XSTR(x) #x
#define STR(x) XSTR(x)

if (STR(NULL)[0] == '(') {
   ...
}

__nullしかし、そこから出てくる可能性のあるものをどのように処理するかはわかりません。

于 2013-01-09T16:06:18.153 に答える
3

マクロを文字列化して文字列を確認できませんでしたか?

# include <stddef.h>
# include <stdio.h>
# include <string.h>

# define STRINGIFY(x) STRINGIFY_AUX(x)
# define STRINGIFY_AUX(x) #x

int main(void)
{
  const char *NULL_MACRO = STRINGIFY(NULL);

  if (strstr("void", NULL_MACRO) != NULL)
    puts("pointer");
  else
    puts("integer");
}

これを追加すると正しく印刷され"integer"ます(通常NULLはピンタータイプです)。

# undef NULL
# define NULL 0

NULL(int) ((void *) 0)整数型に変換されたnullポインタ定数がまだnullポインタ定数であると標準で規定されていないため、のようなものにすることはできません。

さらに、標準では整数定数式(C11、6.6 / 6)についても次のように述べています。

整数定数式117)は整数型であり、整数定数、列挙定数、文字定数、結果が整数定数である式、式、およびキャストの直接のオペランドである浮動定数のみを持つものsizeof_Alignofします。整数定数式のキャスト演算子は、sizeofor_Alignof演算子のオペランドの一部を除いて、算術型を整数型にのみ変換します。

編集:実際には、これは次のようなものでは機能しません:

# define NULL (sizeof(void *) - sizeof(void *))

(気づいてくれてありがとう)そしてこれはOPが必要とするように些細な方法でチェックすることはできません、少しの作業(単純な解析)が必要です。

編集2typedef :そしてコメントとして正しく指摘されているものもあります。

于 2013-01-09T16:07:12.410 に答える
0

ここに1つのあいまいな方法があります: プログラムが式を使用する場合、これは整数型&*NULLを持つとコンパイルされませんが、ポインター型を持つ場合はコンパイルされます。NULLNULL

C99 には、この特殊なケースの文言があります。

[演算子の] オペランド&が単項演算子の結果である場合* 、その演算子も演算子も&評価されず、演算子に対する制約が引き続き適用され、結果が左辺値ではないことを除いて、結果は両方が省略されたかのようになります。 .

演算子の制約には違反していません: のオペランドは単項演算子&の結果であり、単項演算*子のオペランド*はポインター型です (NULLそのように定義されていると想定しているため)。

于 2016-03-10T04:55:11.917 に答える