【问题标题】:Rules of main() function when running at non-startup are the same as at startup?main() 函数在非启动时运行时的规则与启动时相同吗?
【发布时间】:2021-04-08 14:04:49
【问题描述】:

标准中有一些main() 函数的规则。
如果函数被操作系统调用,
argc 的值是非负的,
返回值默认为0等

另一方面,main() 可以被其他函数调用,
因此暗示main()的递归执行。

在这种情况下,如果main()被另一个函数调用,
返回值默认为0还是真的吗,
或者argc 必须是非负数?

【问题讨论】:

  • 默认返回值为零是什么意思?如果返回类型不是void,则需要返回值。如果是int,则需要一个值。
  • @markw main 可以省略return语句,在这种情况下它隐含return 0
  • 1. main 不知道叫什么。它是一个函数:给定相同的输入,除非明确要求,否则它将以相同的方式运行。 2. 标准规定操作系统如何调用main。这并不限制如何显式调用main。如果你想传递一个否定的argc,那是你的选择,但你必须确保你的main 实现处理它。
  • @jamesdlin 我明白你的意思。这是常识告诉我的。然而,标准是棘手的。例如,您的断言 1 不一定正确。该标准区分 main() 的“初始”执行(其中返回就像调用 exit() 一样完成)与否。就您的第 2 点而言,我能够处理像 argc < 0 这样的案例。我的观点是,在提及仅启动情况时,标准可能在这里并不清楚。

标签: c standards c99 c11 c89


【解决方案1】:

正如其他人已经说过的那样,argc 没有任何限制。这些要求在第 5.1.2.2.1 节(程序启动)中表达,因此它们只涉及最初调用 main 时使用的参数。

类似地,在第 5.1.2.2.3 条(程序终止)中可以找到对main 返回规则的放宽。为了更清楚地说明这一点,文本指出这仅涉及对main 的初始调用。文字是

If the return type of the `main` function is a type
compatible with `int`, a return from the initial call
to the `main` function is equivalent to calling the `exit`
function with the value returned by the main
function as its argument; reaching the `}` that terminates 
the `main` function returns a value of `0`.

“;”在短语内清楚地暗示短语开头的条件对于最后一个子短语仍然有效。

所有这些仅在 5.1.2.2(托管环境)内有效,因此独立环境可能会发明自己的规则,但 C 标准并未涵盖这些规则。

【讨论】:

  • 嗨,詹斯。谢谢您的回答。仔细阅读标准后,我同意你的“;”结论。如果假设标题 Program startup 是整个段落的含义,则可以将段落 5.1.2.2.1 解释为您所说的。但是,我仍然认为标准中的措辞并不明确。另一方面,我认为常识决定了您的结论,因为 main() 函数似乎接受任何有效的值集作为非初始调用中的参数(这种信念由其他开发人员共享,正如一些 cmets 在这里展示的那样)。
  • 我接受你的回答,但无论如何我对此事有疑问。谢谢。
【解决方案2】:

关于 return 语句的规则是,如果执行到 main 的末尾而没有遇到 return 语句,那么它的行为就像 return 0; 存在一样。

“只有最外层的 main 调用”或其他任何情况都没有特殊情况。

当然可以用不同的参数值递归调用main——显然,如果你在你的程序中这样做,那么你需要在main中编写代码,以便在定义明确的方式。

C11 标准引用 5.1.2.2.3/1:

如果主函数的返回类型是与int兼容的类型,则初始调用主函数的返回等效于以主函数返回的值作为参数调用exit函数;到达终止主函数的} 返回值0。如果返回类型与 int 不兼容,则返回给宿主环境的终止状态是未指定的。

【讨论】:

  • 感谢您的回答。但是,启动条件会怎样呢?我可以写一个像main( -1, NULL);这样的句子,这样argc < 0。这是对main() 函数的无效调用吗?
  • 顺便说一句,我曾经看到过void main(void *fp);,它并没有看起来那么错误,因为启动代码确实传递了一个void * 指针。不过,今天编译该代码可能会很有趣。
  • @pablo1977:不,不是。如果你传递这样的东西,你必须处理它。
  • @Joshua 可以有实现定义的 main 定义(除了标准定义之外,在托管实现中)
  • 一个相当常见的错误是程序输出argv[0]而不检查argc,错误地假设argv[0]总是保存程序名称
【解决方案3】:

main() 函数没有被操作系统调用。操作系统将可执行文件加载到内存中并控制一段代码:

  • 准备main()的参数并调用它;
  • 获取main()返回的值,并使用特定于操作系统的机制将其传递回操作系统; 当main() 不返回任何内容时,它使用0 作为默认值;
  • 做与讨论无关的其他事情。

这段代码属于你的程序,由标准C库提供。

main() 只是一个普通的函数,除了它的名字没有什么特别之处。例如,Windows 可执行文件使用函数 WinMain() 而不是 main() 用于相同目的。

您可以像调用程序的任何其他函数一样调用main(),并且它的行为方式与程序的任何其他函数相同。

【讨论】:

    猜你喜欢
    • 2012-06-06
    • 1970-01-01
    • 2019-03-10
    • 2013-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多