我可以用 NULL 作为0值的替代吗?

我是否可以使用 NULL指针替换 0的值?

或者这样做有什么不对吗?


比如说:

int i = NULL;

代替:

int i = 0;

作为实验,我编译了以下代码:

#include <stdio.h>


int main(void)
{
int i = NULL;
printf("%d",i);


return 0;
}

产出:

0

事实上,它给了我这样一个警告,这个警告本身是完全正确的:

warning: initialization makes integer from pointer without a cast [-Wint-conversion]

但结果还是等价的。


  • 我是不是已经进入“未定义行为”了?
  • 以这种方式使用 NULL是否允许?
  • 在算术表达式中使用 NULL作为数值有什么问题吗?
  • 在这种情况下,C + + 的结果和行为是什么?

我读过 NULL、0和0之间的区别是什么关于 NULL\00之间的区别是什么的答案,但是我没有从中得到简明的信息,如果它是相当允许的,也是正确的使用 NULL作为值在作业和其他算术运算中操作。

9132 次浏览

免责声明: 我不懂 C + + ,我的回答不适用于 C + +

'\0'是一个值为零的 int,与 0完全相同。

for (int k = 10; k > '\0'; k--) /* void */;
for (int k = 10; k > 0; k--) /* void */;

在指针 的情况下,0NULL是100% 等效的:

if (ptr) /* ... */;
if (ptr != NULL) /* ... */;
if (ptr != '\0') /* ... */;
if (ptr != 0) /* ... */;

都是100% 相同的。


关于 ptr + NULL的注释

ptr + NULL的上下文是指针的 没有。在 C 语言中没有添加指针的定义; 可以添加(或减去)指针和整数。在 ptr + NULL中,如果 ptr或者 NULL是一个指针,那么另一个 ptr + NULL0是一个整数,所以 ptr + NULL实际上是 (int)ptr + NULL或者 ptr + (int)NULL,并且根据 ptrNULL的定义,可以预期几种行为: 全部工作,警告指针和整数之间的转换,编译失败,..。

NULL是一些空指针常量。在 C 语言中,它可以是值为 0的整数常量表达式,也可以是转换为 void*的整数常量表达式,后者更有可能。这意味着 不行假定与零交换使用 NULL。例如,在此代码示例中

char const* foo = "bar";
foo + 0;

NULL替换 0不能保证是一个有效的 C 程序,因为没有定义两个指针之间的加法(更不用说不同的指针类型)。它将导致由于违反约束而发出诊断。用于加法的操作数将无效.


至于 C + + ,情况有些不同。缺乏从 void*到其他对象类型的隐式转换意味着 NULL在 C + + 代码中历史上被定义为 0。在 C + + 03中,您可能不会受到影响。但是因为 C + + 11它可以合法的 被定义为 nullptr关键字。现在再次产生一个错误,因为 std::nullptr_t可能不会被添加到指针类型。

如果 NULL被定义为 nullptr,那么即使你的实验也是无效的。没有从 std::nullptr_t到整数的转换。这就是为什么它被认为是一个更安全的空指针常量。

是否允许我使用 NULL 指针替换0?

不,这样做是不安全的。NULL是一个空指针常量,可以具有 int类型,但是更典型的是 void *类型(在 C 中) ,或者不能直接赋值给 int(在 C + + > = 11中)。这两种语言都允许将指针转换为整数,但是它们都没有隐式地执行这种转换(尽管一些编译器提供了这种扩展)。此外,虽然将空指针转换为整数以产生值0很常见,但标准并不保证这一点。如果您想要一个类型为 int且值为0的常量,那么拼写它为 0

  • 我会不会因为这个闯进未定义行为?

是的,在任何实现中,如果 NULL展开为具有 void *类型的值,或者任何其他不能直接分配给 int的值。标准并没有定义您在这样的实现中赋值的行为,因此它的行为是未定义的。

  • 是否允许以这种方式使用 NULL 操作?

它的风格很差,在某些系统和某些情况下会出现故障。因为您似乎正在使用 GCC,所以如果使用 -Werror选项编译,它将中断您自己的示例。

  • 在算术表达式中使用 NULL 作为数值有什么错误吗?

是的。它根本不能保证有一个数值。如果你的意思是0,那么写0,它不仅定义良好,而且更短更清晰。

  • 那么 C + + 中的结果是怎样的呢?

C + + 语言对转换的要求比 C 更严格,而且对 NULL有不同的规则,但是实现也可以提供扩展。同样,如果你的意思是0,那么这就是你应该写的。

常见问题:

Q: 如果 NULL 和0等价于 NULL 指针常量,我应该使用哪个?

只有在指针上下文中,NULL0才是等价的。当需要另一种类型的0时,应该使用 NULL,即使它可能有效,因为这样做会发送错误的风格信息。(此外,ANSI 允许 NULL 的定义为 ((void *)0),这在非指针上下文中根本不起作用。)特别是,当需要 ASCII 空字符(NUL)时,不要使用 NULL。提供您自己的定义

Http://c-faq.com/null/nullor0.html

我是否可以使用 NULL 指针来替换0的值?

int i = NULL;

规则因语言及其版本而异。在某些情况下,你 可以和在其他情况下,你不能。无论如何,你 不应该。如果幸运的话,编译器会在您尝试时发出警告,或者更好的情况是,编译失败。

在 C + + 中,在 C + + 11之前(引自 C + + 03) :

[ lib.support. type ]

NULL 是本国际标准中实现定义的 C + + 空指针常量。

使用空指针常量作为整数没有什么意义。

[转译]

空指针常量是计算结果为零的整数类型的整数常量表达式(5.19) rvalue。

所以,技术上来说,即使它是荒谬的,它也是可行的。由于这种技术性,您可能会遇到滥用 NULL的拙劣编写的程序。

从 C + + 11开始(引自最新草案) :

[转译]

空指针常量是一个值为 或类型为 std: : nullptr _ t 的值的整数文字([ lex.icon ])。

std​::​nullptr_­t不能转换为整数,因此使用 NULL作为整数只能有条件地工作,这取决于语言实现所做的选择。

P.S. nullptrstd​::​nullptr_­t类型的值。除非需要在 pre-C + + 11中编译程序,否则应该始终使用 nullptr而不是 NULL


C 有点不同(引自 C11草案 N1548) :

6.3.2.3语言/转换/其他操作数/指针

值为0的整数常量表达式 或者这样的表达式转换为 void *类型称为空指针常量。 ..。

因此,这种情况类似于后 C + + 11,即滥用 NULL的工作条件取决于语言实现所做的选择。

Yes ,尽管取决于你的 需要一个强制转换,但是是的,它是100% 合法的,否则。

虽然这是真的,真的,真的很糟糕的风格(不用说?)。

NULL是,或者曾经是,事实上不是 C + + ,它是 C。然而,与许多 C 语言遗产一样,标准的 是的有两个子句([ different.null ]和[ support. typees.nullptr ]) ,它们在技术上使 NULL成为 C + + 。这是 实现定义的空指针常量。因此,即使它的样式很糟糕,它在技术上也是尽可能的 C + + 。
正如在 脚注中指出的,可能的实现可以是 00L,但是 没有 (void*)0

当然,NULL也可以是 nullptr(标准没有明确说明,但是在 00L之后,它几乎是唯一的选择)。几乎从来没有这种情况,但这是一种合法的可能性。

编译器向您显示的警告说明编译器实际上不兼容(除非您以 C 模式编译)。因为,根据警告,它是一个空指针 确实皈依了(而不是 nullptr,它是 nullptr_t的,它是不同的) ,所以显然 NULL的定义确实是 (void*)0,它可能不是。

无论哪种方式,您都有两种可能的合法情况(即编译器没有中断)。无论是(现实的情况) ,NULL是类似于 00L,然后你有 “0或1”转换为整数,你是好去。

或者 NULL确实是 nullptr。在这种情况下,您有一个独特的值,它保证了比较以及明确定义的转换 来自整数,但不幸的是没有 整数。但是,它有一个明确定义的到 bool的转换(导致 false) ,而 bool有一个明确定义的到整数的转换(导致 0)。

不幸的是,这是 转换,所以它不在 “0或1”内,正如[ conv ]中指出的那样。因此,如果您的实现将 NULL定义为 nullptr,那么您必须添加一个显式强制转换来使代码正确。

不,不再喜欢使用 NULL(指针初始化的老方法)。

从 C + + 11开始:

关键字 nullptr表示指针文字。它是 std: : nullptr _ t 类型的一个 prvalue。存在从 nullptr到任何指针类型和任何指向成员类型的空指针值的隐式转换。对于任何空指针常量,都存在类似的转换,空指针常量包括类型 std::nullptr_t的值和宏 NULL的值。

Https://en.cppreference.com/w/cpp/language/nullptr

实际上,Nullptr _ t是空指针文字 nullptr的类型。它是一个独立的类型,本身不是指针类型或指向成员类型的指针。

#include <cstddef>
#include <iostream>


void f(int* pi)
{
std::cout << "Pointer to integer overload\n";
}


void f(double* pd)
{
std::cout << "Pointer to double overload\n";
}


void f(std::nullptr_t nullp)
{
std::cout << "null pointer overload\n";
}


int main()
{
int* pi; double* pd;


f(pi);
f(pd);
f(nullptr);  // would be ambiguous without void f(nullptr_t)
// f(0);  // ambiguous call: all three functions are candidates
// f(NULL); // ambiguous if NULL is an integral null pointer constant
// (as is the case in most implementations)
}

产出:

Pointer to integer overload
Pointer to double overload
null pointer overload