【问题标题】:Why does the compiler parse this as a function pointer and not a recursive call? [duplicate]为什么编译器将其解析为函数指针而不是递归调用? [复制]
【发布时间】:2020-01-28 14:30:54
【问题描述】:

在以下代码中,foo() 在两个不同的地方被解析并调用两个不同的函数(由******** 标记)。

#include <cstdio>

typedef int (*func)(void);

int bar()
{
    printf("bar\n");
    return 4; // guaranteed to be random
}

int foo()
{
    printf("foo\n");
    static int i = 0;
    if(i)
        return i;
    ++i;
    i = foo(); // recursive call     ********
    printf("%d\n", i);
    func foo = bar;
    i = foo(); // calls bar. Why?    ********
    printf("%d\n", i);
    return i;
}

int main()
{
    return foo();
}

在我能够尝试的所有编译器(gcc, clang、MSVC 和其他几个)中,输出是:



1
酒吧
4

为什么编译器选择通过函数指针调用bar并屏蔽递归调用?是否定义了这种行为?如果有,可以给个参考吗?

【问题讨论】:

  • func foo = bar; 表示第二次调用foo 调用bar
  • 为什么要和int i = 5; { int i; i = 6; } assert(i == 5);不同?
  • 对我来说看起来像是常规的名称阴影。 foo 在局部范围阴影 foo 在全局范围内。
  • @Nicol 谢谢你的复制。正是我想要的(特别是 3.3.10.2)。
  • @StoryTeller-UnslanderMonica 我不知道变量隐藏与函数有关。

标签: c++ language-lawyer


【解决方案1】:

是的,此行为已定义,称为名称隐藏、范围隐藏或阴影。请参阅 Victor Polevoy 的 this answer,下面引用的相关部分。

来自N4296

3.3.10 名称隐藏 [basic.scope.hiding]

  1. 可以通过在嵌套声明区域或派生类中显式声明相同名称来隐藏名称。
  2. 类名 (9.1) 或枚举名 (7.2) 可以被声明的变量、数据成员、函数或枚举器的名称隐藏 相同的范围。如果一个类或枚举名称和一个变量,数据 成员、函数或枚举器在同一范围内声明(在任何 order) 同名,隐藏类名或枚举名 变量、数据成员、函数或枚举器名称在哪里 可见。
  3. 在成员函数定义中,块范围内的名称声明隐藏了具有相同名称的类成员的声明 姓名;见 3.3.7。派生类中成员的声明 (第 10 条)隐藏基类成员的声明 一样的名字;见 10.2。
  4. 在查找由命名空间名称限定的名称期间,原本可以通过 using 指令可见的声明 可以被命名空间中同名的声明隐藏 包含使用指令;见 (3.4.3.2)。
  5. 如果名称在范围内且未隐藏,则称其为可见

在这种情况下也是第1点:函数中名称foo的声明隐藏了外部作用域中函数名称foo的声明。

【讨论】:

  • 当你复制一些东西时,你需要阻止引用它。此外,如果您复制了某些内容,并且您的所有/大部分内容都是复制的内容,那么即使您引用它也是抄袭。
  • 不,这里发生的事情不是第 3 点。我们不在成员函数中,被遮蔽的不是类成员的声明。
  • 对,误读了 sn-p @foreknownas_463035818
  • @NathanOliver 我认为当最终从维克多的答案中复制的唯一原始内容是“来自 N4296”的词时,调用该论点是过分的。但是,我确实同意最好至少在块引用中包含它和标题,以非常清楚地表明它不是我写的。
猜你喜欢
  • 1970-01-01
  • 2021-12-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-07
  • 2012-04-23
  • 1970-01-01
  • 2020-09-06
相关资源
最近更新 更多