NULL宏什么时候不是0?
我依稀记得几年前读过这篇文章,但我在网上找不到任何参考资料。
你能给我一个 NULL 宏没有扩展到 0 的例子吗?
为清楚起见进行编辑:今天它扩展为 ((void *)0)
、(0)
或 (0L)
。然而,有些架构早已被遗忘,但事实并非如此,并且 NULL 扩展到不同的地址。就像
#ifdef UNIVAC
#define NULL (0xffff)
#endif
我正在寻找这样一台机器的例子。
更新以解决问题:
我并不是在当前标准的背景下提出这个问题,也不是为了让人们因为我的错误术语而感到不安。然而,我的假设得到了公认的答案的证实:
后来的模型使用了[废话],显然是为了对所有现存的写得不好的 C 代码做出错误的假设。
有关当前标准中空指针的讨论,请参阅
I vaguely remember reading about this a couple of years ago, but I can't find any reference on the net.
Can you give me an example where the NULL macro didn't expand to 0?
Edit for clarity: Today it expands to either ((void *)0)
, (0)
, or (0L)
. However, there were architectures long forgotten where this wasn't true, and NULL expanded to a different address. Something like
#ifdef UNIVAC
#define NULL (0xffff)
#endif
I'm looking for an example of such a machine.
Update to address the issues:
I didn't mean this question in the context of current standards, or to upset people with my incorrect terminology. However, my assumptions were confirmed by the accepted answer:
Later models used [blah], evidently as a sop to all the extant poorly-written C code which made incorrect assumptions.
For a discussion about null pointers in the current standard, see this question.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
C FAQ 有一些具有非 0 NULL 表示的历史机器的示例。
来自C 常见问题解答列表,问题 5.17:
The C FAQ has some examples of historical machines with non-0 NULL representations.
From The C FAQ List, question 5.17:
很久以前,它被键入为
((void*)0)
或其他某种特定于机器的方式,其中该机器不使用全零位模式。某些平台(某些 CDC 或 Honeywell 机器)对 NULL 有不同的位模式(即不是全零),尽管 ISO/ANSI 在 C90 批准之前通过指定
0 修复了这一点。 code> 是源代码中正确的 NULL 指针,无论底层位模式如何。来自
C11 6.3.2.3 Pointers /4
(不过,如上所述,这个措辞可以一直追溯到 C90):There was a time long ago when it was typed as
((void*)0)
or some other machine-specific manner, where that machine didn't use the all-zero bit pattern.Some platforms (certain CDC or Honeywell machines) had a different bit pattern for NULL (ie, not all zeros) although ISO/ANSI fixed that before C90 was ratified, by specifying that
0
was the correct NULL pointer in the source code, regardless of the underlying bit pattern. FromC11 6.3.2.3 Pointers /4
(though, as mentioned, this wording goes all the way back to C90):在 C 编译器中,它可以扩展为“
((void *)0)
”(但不必这样做)。这不适用于 C++ 编译器。另请参阅 C 常见问题解答,其中有一整章介绍 空指针。
In C compilers, it can expand to '
((void *)0)
' (but does not have to do so). This does not work for C++ compilers.See also the C FAQ which has a whole chapter on null pointers.
在 GNU libio.h 文件中:
注意 __cplusplus 上的条件编译。 C++ 不能使用 ((void*) 0),因为它对指针转换有更严格的规则;标准要求 NULL 为 0。C 允许 NULL 的其他定义。
In the GNU libio.h file:
Note the conditional compilation on __cplusplus. C++ can't use ((void*) 0) because of its stricter rules about pointer casting; the standard requires NULL to be 0. C allows other definitions of NULL.
C 编译器通常使用
((void *)0)
。原因是将NULL
传递给具有可变参数的函数(或者现在很少见但仍然合法的没有原型的函数)。当指针大于 int 时,0
只会提升为int
,因此无法正确读取为指针。C++ 编译器无法使用该定义,因为 C++ 不允许从
void *
进行隐式转换(将0
转换为任何指针都是特殊情况)。然而,C++11 引入了新关键字nullptr
,它是特殊nullptr_t
类型的空指针常量,可隐式转换为任何指针类型,但不能转换为数字。这解决了可变参数问题和隐式强制转换,以及重载选择方面更严重的问题(0
出于明显的原因选择int
重载而不是指针 1)。为较旧的编译器自行定义这些是合法的,并且一些 C++ 编译器过去尝试过这样做。C compilers usually use
((void *)0)
. The reason is passingNULL
to functions with variable arguments (or now rare but still legal functions without prototype). When pointers are larger than int,0
will only be promoted toint
and will thus not read correctly as pointer.C++ compilers can't use that definition because C++ does not permit implicit cast from
void *
(casting0
to any pointer is special-cased). However C++11 introduced new keywordnullptr
that is a null pointer constant of specialnullptr_t
type implicitly convertible to any pointer type, but not number. This solves both the variadic argument problem and the implicit cast and additionally more severe problems with overload selection (0
for obvious reason selectsint
overload over pointer one). It is legal to define these yourself for older compilers and some C++ compilers tried that in the past.在现代 C 语言中,
void *pointer = 0;
旨在将“指针”初始化为不指向任何东西。是否通过将“指针”位设置为全零来实现这一点是特定于平台的。过去,指针上下文中“0”的这种正式含义尚未建立。有必要将指针设置为平台视为“不指向任何地方”的实际值。例如,平台可能会选择一些永远不会将页面映射到它的固定地址。在这种情况下,在旧的编译器中,平台可能将
NULL
定义为:当然,今天,没有理由不将其定义为
((void*)0)
。In modern C,
void *pointer = 0;
is meant to initialize "pointer" to not point at anything. It is platform-specific as to whether that is accomplished by setting the bits of "pointer" to all-zero.In the past, this formal meaning of "0" in a pointer context was not established. It was necessary to set the pointer to the actual value that the platform treated as "doesn't point anywhere". As an example, a platform might choose some fixed address that never gets a page mapped to it. In this case, in an old compiler, the platform might have defined
NULL
as:Of course, today, there's no reason not to define it as
((void*)0)
.C 中的
NULL
宏扩展为实现定义的空指针常量。它可以是任何东西(因为它是实现定义的),但在指针上下文中,效果始终与扩展为常量0
相同。在标准 C 历史中,从未有过
NULL
扩展到特定非0
的情况,除非您将(void *) 0
视为“不是 0”。但代表NULL
的(void *) 0
至今仍被广泛使用。NULL
macro in C expands to implementation defined null-pointer constant. It can be anything (since it is implementation-defined), but in pointer context the effect is always the same as if it expanded to constant0
.There has never been a time in standard C history when
NULL
expanded to something specifically not0
, unless you consider(void *) 0
as "not 0". But(void *) 0
forNULL
is widely used to this day.