【问题标题】:About Initializing Pointers in C++ [duplicate]关于在 C++ 中初始化指针 [重复]
【发布时间】:2020-04-22 14:28:22
【问题描述】:

我一直在阅读 C++ Primer 5th edition。它提到了

将 int 变量赋值给指针是非法的,即使该变量的值恰好是 0。

我试了一下,结果如下:

int *u = 0; // success

int *w = 123; // fail 
/* compile error:
ptr_test.cc:9:12: error: invalid conversion from 'int' to 'int*' [-fpermissive]
    int *w = 123;
*/


int zero = 0;
int *v = zero; // fail
/* compile error
ptr_test.cc:9:12: error: invalid conversion from 'int' to 'int*' [-fpermissive]
    int *w = zero;
*/

谁能帮我解释一下指针初始化的确切规则? 为什么将 int 指针分配给 0 很好,但 123 不行,尽管它们都是整数?为什么 123 会导致转换为 "*int" 而 0 不会?

顺便说一句,我使用的是 g++ (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0。

【问题讨论】:

  • 查看我提供的解释“类型转换”的链接。
  • 接受 0 作为 null 是一种约定。当您尝试将zero(=0) 归因于*v 时,也有一个例外。因为当编译器解析等于某个指针的0 时,它们会将值评估为NULL。但是当您尝试使*v=zero 时,编译器首先匹配变量的类型并找到一个是指针另一个是int(这不会发生在*v=0 上,因为0 被异常处理)。

标签: c++ pointers


【解决方案1】:

为什么将 int 指针赋值为 0 就可以了

因为 0 除了是整数字面量外,也是一个空指针常量。并且空指针常量可以转换为任何指针类型。

但是123不行

因为 123 或除值为 0 之外的任何其他整数文字都不是空指针常量。并且整数表达式(空指针常量除外)不会隐式转换为指针类型。

为什么 123 会导致转换为 "*int" 而 0 不会?

两者都不会“导致演员表”。 Cast 是显式转换,在这些示例中,所有转换都是隐式的。从整数到指针的隐式转换是格式错误的,这就是您收到错误的原因。空指针转换是隐式且格式正确的,这就是您不会收到错误的原因。

谁能帮我解释一下确切的规则

这里是确切的规则(引用最新的 C++ 标准草案):

[conv.ptr]

空指针常量是一个整数文字 ([lex.icon]),其值为 0 或类型为 std​::​nullptr_­t 的纯右值。 空指针常量可以转换为指针类型;结果是该类型的空指针值([basic.compound]),并且可以与对象指针或函数指针类型的所有其他值区分开来。 这种转换称为空指针转换。 ...

附:关键字nullptrstd​::​nullptr_­t 类型的纯右值。除非您打算支持 C++11 之前的编译器,否则它应该始终优于使用文字 0。

【讨论】:

    【解决方案2】:

    C++ 对 literal 整数 0 有一个特殊情况,它可以隐式转换为空指针。

    【讨论】:

      【解决方案3】:

      int *u = 0;被视为空值。所以,这将是一个空指针。其他错误来自“类型转换”。 int *w是一个新的int类型指针的声明,所以一个整数值不能等于一个指针。 这将使您更好地了解正在发生的事情:
      https://www.cprogramming.com/tutorial/lesson11.html
      接受 0 作为 null 是一种约定。当您尝试将zero(=0) 归因于*v 时,也会发生错误。因为当编译器解析等于某个指针的0 时,它们会评估0 并将其替换为NULL。但是当您尝试创建*v=zero 时,编译器首先匹配变量的类型并找到一个是指针,另一个是int(这不会发生在*v=0 上,因为0 被异常处理)。

      【讨论】:

      • 我记得,NULL被定义为0
      • int *ptr = NULLint *ptr = 0 产生相同的结果。虽然 0 是 int,但您可以将 0 归为指针的值,按照惯例,它将是空指针。
      • 错误不是来自“类型转换”。它来自 conversion 类型。强制转换是您在源代码中编写的内容,用于告诉编译器进行转换。
      【解决方案4】:

      这是 Stroustrup 对此的看法:C++ Style and Technique FAQ

      在C++中,NULL的定义是0,所以只有审美上的区别。我更喜欢避免使用宏,所以我使用 0。NULL 的另一个问题是人们有时会错误地认为它不同于 0 和/或不是整数。在准标准代码中,NULL 有时被/被定义为不合适的东西,因此必须/必须避免。现在这种情况不太常见了。

      也就是说,如果您将0 与指针一起使用,它会产生NULL - 只是0 的特权。

      【讨论】:

        【解决方案5】:

        为什么给int指针赋值为0就好了,但123就不行了,虽然它们都是整数?

        0 是允许分配 NULL 的特殊情况,通常定义如下:
        #define NULL 0

        在 C++11 中,您可能会发现它是这样定义的:
        #define NULL nullptr

        随着 C++11 的添加 nullptr 可能会在将来的某个时间删除特殊情况。

        【讨论】:

          【解决方案6】:

          其他答案已经充分描述了 literal expression 0 可以是空指针常量这一事实。但是他们还没有出来解释为什么你的书也是正确的。让我们重复您的引文,并稍加突出显示。

          将 int variable 分配给指针是非法的,即使该变量的值恰好为 0。

          让您感到困惑的是0 不是变量。这意味着下面的代码是非法的:

          int i = 0;   // int variable with value 0
          int *ip = i; // nope, won't work
          

          当然,您的书可能使用“变量”一词误导了您。这适用于所有 objects,而不仅仅是那些有名字的人。

          【讨论】:

          • 变量是 C++ 标准中的官方技术术语:timsong-cpp.github.io/cppwp/basic#pre-6。语句int i = 0; 定义了一个变量,而在语句int *ip = i; 中,表达式i 命名了同一个变量。具有对象类型且具有定义的变量表示一个对象,但并非每个对象都有一个变量。
          猜你喜欢
          • 2018-01-09
          • 1970-01-01
          • 1970-01-01
          • 2017-08-26
          • 1970-01-01
          • 2016-03-12
          • 2015-05-01
          • 1970-01-01
          • 2017-10-18
          相关资源
          最近更新 更多