【问题标题】:C++ declare 'main' as a reference to function?C ++声明'main'作为对函数的引用?
【发布时间】:2015-04-13 14:34:09
【问题描述】:

如果我将 main 定义为对函数的引用会怎样?

#include<iostream>
#include<cstring>

using namespace std;

int main1()
{
    cout << "Hello World from main1 function!" << endl;
    return 0;
}

int (&main)() = main1;

会发生什么?我在在线编译器中测试了错误“分段错误”:

here

而且在 VC++ 2013 下会造成程序在运行时崩溃!

将函数指针的数据作为代码调用的代码将被编译,该代码将在启动时立即崩溃。

我还想要一份关于此的 ISO C++ 标准引用。

如果您想根据类似这样的宏定义 2 个入口点中的任何一个,该概念将非常有用:

int main1();

int main2();

#ifdef _0_ENTRY
int (&main)() = main1;
#else
int (&main)() = main2;
#endif

【问题讨论】:

  • 我认为您要求很高,希望 ISO 标准能够解决这种疯狂的行为。
  • 有趣的是,该标准实际上并没有禁止在独立实现中构建的代码定义一个名为 main 的全局符号,它不是一个函数,尽管它确实在该符号上施加了其他保留命名空间。
  • @ChristianHackl 该标准已经跨越 1300 页。如果它必须详细说明程序员想做的每一件疯狂的事情,那么没人会阅读它。
  • @remyabel:事实上,正如问题的答案所示,标准确实定义了是否允许OP的代码。它必须;根据定义,该标准涵盖了所有可以想象的代码,并告诉您它是否有效。 IWO,无论多么疯狂,标准中没有一段代码“我不在乎这是否是未定义的行为”。
  • @remyabel:它在 [basic.start.main]/3 中这么说。 “函数main 不得在程序中使用。”这包括使用它来初始化引用。 (这与问题无关,即main 被允许成为什么样的实体。)

标签: c++ reference main language-lawyer iso


【解决方案1】:

这不是一个符合 C++ 标准的程序。 C++ 要求(第 3.6.1 节)

程序应包含一个名为main的全局函数

您的程序包含一个名为 main 的全局非函数,它与必需的 main 函数产生名称冲突。


这样做的一个理由是它允许托管环境在程序启动期间对main 进行函数调用。它不等同于源字符串main(args),它可以是函数调用、函数指针解引用、在函数对象上使用operator(),或者构造main 类型的实例。不,main 必须是一个函数。

另外需要注意的是,C++ 标准从未说明 main 的实际类型是什么,并且阻止您观察它。因此实现可以(并且做!)重写签名,例如添加您省略的任何int argc, char** argv, char** envp。显然它不知道为您的main1main2 执行此操作。

【讨论】:

  • 您的报价不完整。紧随其后的是“独立环境中的程序是否需要定义主要功能是实现定义的。”并且没有规定这样的程序不能在名为 main 的全局命名空间(p3:“将 main 定义为已删除或将 main 声明为内联、静态或 constexpr 的程序格式错误。名称 main 未保留。[示例:成员函数、类和枚举可以称为 main,其他命名空间中的实体也可以。—结束示例 ]")。
  • 话虽如此,我认为我们可以假设 OP 没有使用这样的实现。 :) 但也许这一切都会改善这个答案?
  • @LightnessRacesinOrbit:有趣的是,他们选择将这条规则写成一个普遍的陈述,然后是一个矛盾,没有太多的“例外”。肯定不难说“托管环境中的程序应包含名为main 的全局函数”或“程序应包含名为main 的全局函数,但在独立环境中它是实现-定义...”
  • 我同意。措辞一直困扰着我(当它随后被误解时,似乎引发了一些互联网争论!)。
【解决方案2】:

如果您想根据某个宏定义 2 个入口点中的任何一个,这将很有用

不,不是真的。你应该这样做:

int main1();
int main2();

#ifdef _0_ENTRY
   int main() { return main1(); }
#else
   int main() { return main2(); }
#endif

【讨论】:

  • 是的,但至少对我来说,只分配一个函数引用似乎更直观。否则,我们将定义另一个函数,这不是我想要的。
  • 这是一个不错且不显眼的解决方案。
  • @FISOCPP:我真的不明白为什么不这样做。此外,您别无选择。 :)
  • 我从来没有说过这很糟糕。我只是觉得我的版本似乎更直观。
  • @FISOCPP:我认为你的版本一点也不直观,但我想每个版本都有自己的。
【解决方案3】:

由于CWG issue 1886 的决议,这很快就会变得明显不正确,目前处于“暂时准备就绪”状态,除其他外,它在 [basic.start.main] 中添加了以下内容:

在全局范围内声明变量 main 的程序或 使用 C 语言链接(在任何命名空间中)声明名称 main 是 格式不正确。

【讨论】:

  • 也许他们应该更好地允许“主”函数引用作为规则的例外。
  • @FISOCPP:实施起来会非常复杂。 main 必须是可由 C++ 运行时调用的简单函数。像你提议的那样引入复杂性是不值得的。
【解决方案4】:

在实践中会发生什么在很大程度上取决于实施。

在您的情况下,您的编译器显然将该引用实现为“变相的指针”。除此之外,指针具有外部链接。 IE。您的程序导出一个名为main 的外部符号,它实际上与指针占用的数据段中的内存位置相关联。链接器无需过多研究,就将该内存位置记录为程序的入口点。

稍后,尝试将该位置用作入口点会导致分段错误。首先,该位置没有有意义的代码。其次,仅仅尝试将控制权传递给数据段内的某个位置可能会触发您平台的“数据执行保护”机制。

通过这样做,您显然希望引用将得到优化,即 main 将成为 main1 的另一个名称。在你的情况下,它没有发生。该引用作为一个独立的外部对象保留下来。

【讨论】:

    【解决方案5】:

    看起来你已经回答了关于会发生什么的问题。

    至于为什么,在您的代码中main 是一个函数的引用/指针。这与函数不同。如果代码调用的是指针而不是函数,我预计会出现段错误。

    【讨论】:

      猜你喜欢
      • 2014-02-25
      • 1970-01-01
      • 1970-01-01
      • 2017-10-11
      • 2019-09-22
      • 1970-01-01
      • 2018-03-28
      • 1970-01-01
      • 2020-04-07
      相关资源
      最近更新 更多