【问题标题】:Default value of a function pointer in C++C++中函数指针的默认值
【发布时间】:2013-01-27 13:25:14
【问题描述】:

C++ 中函数指针的默认值是多少? (显然不可能是NULL,那是什么?)

这个程序应该如何表现以及为什么?

struct S { void (*f)(); };

int main()
{
    S s = S();
    s.f();   // What is the value of s.f?
}

【问题讨论】:

  • (显然不可能是NULL, ...)。为什么?
  • @Mehrdad:是的,你错了。
  • @Angew:嗯... 任何指针?所以你的意思是即使 member 函数指针也可以为空?
  • @Mehrdad 也许当指针为空时它正在处理极端情况?即当指针指向没有函数时调用默认处理程序。
  • @Angew 不能将宏 NULL 定义为 ((void*)0) 的原因是因为 C++ 标准规定不能。 0 的类型为 int,除特殊措辞外,不能分配给任何指针。 ((void*)0) 具有 void* 类型,除了 C 标准中的特殊措辞外,不能将其分配给 C 中的函数指针。这两个标准都包含允许空指针常量破坏类型系统的特殊语言。 C++使用传统定义;出于某种原因,C 委员会在空指针常量中扩展了合法类型。

标签: c++ function-pointers


【解决方案1】:

第一个 any 指针可以为空。这是关于指针的一个普遍真理。也就是说,您的为空,但不一定出于您可能认为的原因;

C++11 § 8.5,p10

初始化器为空括号集的对象,即(),应值初始化

这很重要,因为您的声明包含以下内容:

S s = S();

值初始化的定义

C++11 § 8.5,p7

对 T 类型的对象进行值初始化意味着:

  • 如果 T 是具有用户提供的构造函数 (12.1) 的(可能是 cv 限定的)类类型(第 9 条),则调用 T 的默认构造函数(如果 T没有可访问的默认构造函数);

  • 如果 T 是(可能是 cv 限定的)非联合类类型,没有用户提供的构造函数,则该对象是零初始化,并且如果 T 是隐式声明的默认值构造函数是不平凡的,构造函数被调用。

  • 如果T是数组类型,那么每个元素都是值初始化的;

  • 否则,对象将零初始化。

这让我们明白了零初始化的对象类型意味着什么:

C++11 § 8.5,p5

对 T 类型的对象或引用进行零初始化意味着:

  • 如果T是标量类型(3.9),则对象设置为值0(零),取整型常量表达式,转换为T(103)

  • 如果 T 是(可能是 cv 限定的)非联合类类型,每个非静态数据成员和每个基类子对象都被零初始化并且填充被初始化为零位;

  • 如果 T 是(可能是 cv 限定的)联合类型,则对象的第一个非静态命名数据成员初始化为零,填充初始化为零位;

  • 如果T是数组类型,每个元素都初始化为零;

  • 如果 T 是引用类型,则不执行初始化。

103) 如 4.10 所述,将值为 0 的整型常量表达式转换为指针类型会导致 空指针值

后者是你的指针为空的原因。 不会保证标准给出相同的代码,但将s的声明更改为:

S s;

鉴于上述声明,标准采用了不同的路径:

C++11 § 8.5,p11

如果没有为对象指定初始化器,则该对象为默认初始化;如果不执行初始化,则具有自动或动态存储持续时间的对象具有不确定的值。 [注意:具有静态或线程存储持续时间的对象是零初始化的,请参阅 3.6.2。

然后引出最后一个问题,默认初始化是什么

C++11 § 8.5,p6

默认初始化 T 类型的对象意味着:

  • 如果 T 是(可能是 cv 限定的)类类型(第 9 条),则调用 T 的默认构造函数(如果 T 没有可访问的默认构造函数,则初始化是非良构的);

  • 如果T是数组类型,每个元素都是默认初始化的;

  • 否则,不执行初始化。

【讨论】:

  • 哦,“A”代表努力 :-)
  • 我实际上知道初始化,这就是我这样做的原因......但是无论如何都要提到它+1哈哈。
  • 一大堆标准引号只是为了说“函数指针的默认值为NULL”?
  • @Puppy 不是说它可以为NULL;它是如何到达那里的。它通过初始化到达那里,初始化的方法对于它的最终值至关重要。如果您所说的逐字逐句普遍正确,“函数指针的默认值为NULL”,那就没关系了。它不是,它确实如此。
【解决方案2】:

在您的情况下,对象 s 是零初始化的,这意味着函数指针是 NULL

struct S { void (*f)(); };

int main()
{
    S s = S();
    if ( s.f == NULL)
       std::cout << "s.f is NULL" << std::endl;
}

输出:

s.f is NULL

Online demo.

【讨论】:

  • @KerrekSB:是的,让我的生活更轻松地在它们之间进行选择! xD
【解决方案3】:

函数指针可以为 NULL,您可以将 NULL 分配给它。比如看看here

#include <iostream>

using namespace std;

struct S { void (*f)(); };

int main()
{
    S s = S();
    s.f = NULL;
    return 0;
}

我相信你调用结构的构造函数的方式(带有()),f 将是NULL。

【讨论】:

    【解决方案4】:

    函数指针可以为NULL,这样就可以表明它们不指向任何东西!

    【讨论】:

      【解决方案5】:

      在 C++(和 C)中,指针(不论类型)没有默认值本身;他们把当时发生在记忆中的东西拿走。但是,它们确实有一个默认的初始化值NULL

      默认初始化

      当您没有显式定义构造函数时,C++ 将调用每个成员变量的默认初始化程序,这将初始化指向0 的指针。但是,如果你定义了一个构造函数,但没有为指针设置值,它就没有默认值。整数、浮点数和双精度数的行为是相同的。

      一边

      int main()
      {
          S s = S();
          s.f();   // <-- This is calling `f`, not getting the pointer value.
      }
      

      【讨论】:

      • 嗯?我想如果我说struct P { void *p; }; P p = P(); 那么p.p 一定是NULL,不是吗?
      • @Mehrdad 我会尽量澄清。
      • @Alex: S s;S s = S(); 是两个*不同的东西!请注意,S 是 POD。
      猜你喜欢
      • 2015-05-04
      • 2012-04-03
      • 1970-01-01
      • 1970-01-01
      • 2015-04-06
      • 2013-08-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多