标准的C实现的#define NULL可以是古怪的东西 [英] Can a conforming C implementation #define NULL to be something wacky

查看:145
本文介绍了标准的C实现的#define NULL可以是古怪的东西的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我问,因为在的讨论螺纹。

想有使用在其他人的答复意见一个严重的背部和往复讨论是不容易的或有趣。所以我想听听我们的C专家认为没有在同一时间被限制为500个字符。

C标准有precious几句话要说约 NULL 和空指针常量。有只有两个,我可以找到相关章节。第一:


  

3.2.2.3指针


  
  

这是整型常量前pression与
  值0,或者这样的前pression
  转换为类型为void *,被称为空
  指针常量。如果一个空指针
  常数被分配给或比较
  平等为指针,
  常数被转换为一个指针
  该类型。这样一个指针,称为
  空指针,是保证比较
  不等的指针的任何对象或
  功能。


和第二个:


  

4.1.5通用定义


  
  

的宏

  NULL


  
  

它扩展成一个实现定义的空指针常数;


现在的问题是,能 NULL 扩展到一个实现定义的空指针常量,它是从3.2.2.3列举的那些不同?

在具体而言,可以将其定义为:

 的#define NULL __builtin_magic_null_pointer

甚至

 的#define NULL((无效*) -  1)

我的阅读3.2.2.3是,它指定为0的整型常量前pression和投0中不可或缺的不断前pression void *类型必须是空指针常量的形式之一该实现可识别的,但它并不意味着是详​​尽的清单。我认为,实现可以自由地承认其他源代码构造为空指针常数,所以只要没有其他规则被打破。

因此​​,例如,它是可证明的那

 的#define NULL(-1)

不是一个法律定义,因为在

 如果(NULL)
   做东西();

do_stuff()不能被调用,而以

 如果(-1)
   做东西();

do_stuff()必须被调用;因为它们是等价的,这不可能是 NULL 的法律定义。

不过,标准说整数到指针的转换(反之亦然)的实现定义,因此可以定义一个指针产生一个空指针转换-1的转换。在这种情况下

  IF((无效*) -  1)

将评估为假,一切都会很好。

所以,不要其他人的想法是什么?

我要问大家特别是牢记为假设规则在描述2.1.2.3程序执行。这是巨大的,有点迂回,所以我在这里不糊,但它本质上说,一个实现仅具有与所需的标准描述的抽象机来生产同样观察到的副作用。它说,任何优化,转换,或任何其他编译器想做你的程序是完全合法的,只要程序的可观察到的副作用不被他们改变。

所以,如果你正在寻找证明 NULL 的特定定义不能是合法的,你需要拿出一个程序,可以证明这一点。任何一个像我这样的公然破坏其他条款的标准,或者一个可以合法侦测魔法什么的编译器做才能让陌生的NULL定义的工作。

史蒂夫·杰索普发现的方法的例子一个程序来检测 NULL 不是定义为在3.2.2.3两种形式的空指针常量之一,这是stringize常数:

 的#define stringize_helper(X)#X
#定义stringize(X)stringize_helper(X)

使用这个宏,我们可以

 看跌期权(stringize(NULL));

和检测是NULL不会扩展到3.2.2.3的形式之一。那是足以让其他定义是否违法?我只是不知道。

谢谢!


解决方案

在C99标准,§7.17.3指出 NULL 扩展为定义的实施空指针常量的。同时§6.3.2.3.3定义的空指针常量的作为,其值为0,或者这样的前pression投整型常量前pression键入无效* 。由于没有一个空指针常量没有其他的定义,符合标准的定义 NULL 必须扩大到整型常量前$ P $零值pssion(或该投给无效* )。

另外从ÇFAQ报价问题5.5 (强调):


C标准的第4.1.5条规定,NULL扩展为实现定义的空指针常量,这意味着实现就可以选择使用哪种0的形式和是否使用`无效*`投;见问题5.6和5.7。 实现定义,这里的并不意味着NULL可能#defined,以满足一些具体的实现非零内部空指针值

它的意义;因为标准要求指针上下文零整数常数的编译的成空指针(无论该机器的内部重新$的是p $ psentation是否有值为零)的情况下 NULL 定义为零,必须无论如何处理。程序员无需键入 NULL 来获得空指针;它只是一个风格约定(并可能有助于捕获错误,例如一个 NULL 定义为(无效*)0 时使用在非指示器上下文)。

编辑:混乱的一个根源在这里似乎是由标准所使用的语言简练,即它并没有明确说是没有的其他的可能被视为一个空指针恒定值。然而,当标准说...被称为空指针常数,则意味着<青霉>准确的给定的定义被称为空指针常数。它并不需要通过阐明什么不合格时(根据定义)的标准定义了的的一致。

明确遵循每个定义

I'm asking because of the discussion that's been provoked in this thread.

Trying to have a serious back-and-forth discussion using comments under other people's replies is not easy or fun. So I'd like to hear what our C experts think without being restricted to 500 characters at a time.

The C standard has precious few words to say about NULL and null pointer constants. There's only two relevant sections that I can find. First:

3.2.2.3 Pointers

An integral constant expression with the value 0, or such an expression cast to type void * , is called a null pointer constant. If a null pointer constant is assigned to or compared for equality to a pointer, the constant is converted to a pointer of that type. Such a pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.

and second:

4.1.5 Common definitions

The macros are

NULL

which expands to an implementation-defined null pointer constant;

The question is, can NULL expand to an implementation-defined null pointer constant that is different from the ones enumerated in 3.2.2.3?

In particular, could it be defined as:

#define NULL __builtin_magic_null_pointer

Or even:

#define NULL ((void*)-1)

My reading of 3.2.2.3 is that it specifies that an integral constant expression of 0, and an integral constant expression of 0 cast to type void* must be among the forms of null pointer constant that the implementation recognizes, but that it isn't meant to be an exhaustive list. I believe that the implementation is free to recognize other source constructs as null pointer constants, so long as no other rules are broken.

So for example, it is provable that

#define NULL (-1)

is not a legal definition, because in

if (NULL) 
   do_stuff(); 

do_stuff() must not be called, whereas with

if (-1)
   do_stuff();

do_stuff() must be called; since they are equivalent, this cannot be a legal definition of NULL.

But the standard says that integer-to-pointer conversions (and vice-versa) are implementation-defined, therefore it could define the conversion of -1 to a pointer as a conversion that produces a null pointer. In which case

if ((void*)-1) 

would evaluate to false, and all would be well.

So what do other people think?

I'd ask for everybody to especially keep in mind the "as-if" rule described in 2.1.2.3 Program execution. It's huge and somewhat roundabout, so I won't paste it here, but it essentially says that an implementation merely has to produce the same observable side-effects as are required of the abstract machine described by the standard. It says that any optimizations, transformations, or whatever else the compiler wants to do to your program are perfectly legal so long as the observable side-effects of the program aren't changed by them.

So if you are looking to prove that a particular definition of NULL cannot be legal, you'll need to come up with a program that can prove it. Either one like mine that blatantly breaks other clauses in the standard, or one that can legally detect whatever magic the compiler has to do to make the strange NULL definition work.

Steve Jessop found an example of way for a program to detect that NULL isn't defined to be one of the two forms of null pointer constants in 3.2.2.3, which is to stringize the constant:

#define stringize_helper(x) #x
#define stringize(x) stringize_helper(x) 

Using this macro, one could

puts(stringize(NULL));

and "detect" that NULL does not expand to one of the forms in 3.2.2.3. Is that enough to render other definitions illegal? I just don't know.

Thanks!

解决方案

In the C99 standard, §7.17.3 states that NULL "expands to an implementation defined null pointer constant". Meanwhile §6.3.2.3.3 defines null pointer constant as "an integer constant expression with the value 0, or such an expression cast to type void *". As there is no other definition for a null pointer constant, a conforming definition of NULL must expand to an integer constant expression with the value zero (or this cast to void *).

Further quoting from the C FAQ question 5.5 (emphasis added):

Section 4.1.5 of the C Standard states that NULL "expands to an implementation-defined null pointer constant," which means that the implementation gets to choose which form of 0 to use and whether to use a `void *` cast; see questions 5.6 and 5.7. "Implementation-defined" here does not mean that NULL might be #defined to match some implementation-specific nonzero internal null pointer value.

It makes perfect sense; since the standard requires a zero integer constant in pointer contexts to compile into a null pointer (regardless of whether or not the machine's internal representation of that has a value of zero), the case where NULL is defined as zero must be handled anyhow. The programmer is not required to type NULL to obtain null pointers; it's just a stylistic convention (and may help catch errors e.g. when a NULL defined as (void *)0 is used in a non-pointer context).

Edit: One source of confusion here seems to be the concise language used by the standard, i.e. it does not explicitly say that there is no other value that might be considered a null pointer constant. However, when the standard says "…is called a null pointer constant", it means that exactly the given definitions are called null pointer constants. It does not need to explicitly follow every definition by stating what is non-conforming when (by definition) the standard defines what is conforming.

这篇关于标准的C实现的#define NULL可以是古怪的东西的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆