C++ 在 main() 结束时返回 [关闭]

Posted

技术标签:

【中文标题】C++ 在 main() 结束时返回 [关闭]【英文标题】:C++ return at the end of main() [closed] 【发布时间】:2013-08-07 20:33:38 【问题描述】:

我正在考虑实现我自己的 exit() 函数,仅用于教育目的。我知道如果操作系统允许您可以操作地址(例如操作系统不会让您操作地址 0,它会导致崩溃)。 所以我想为什么不将0发送到return 0返回的那个地址。

int main()
// code...
return 0;

return 0 向操作系统返回“成功”,对吗?但它是哪个地址?我如何得到它? C 标准库中的实际 exit() 是否以这种方式实现?

【问题讨论】:

我认为您可以避免对这些“操作系统允许您操作的地址”的一些误解 你的问题真的没有多大意义。你应该试着澄清一下。 return 0;main 函数返回 0。 C++ 标准没有指定从函数返回时要跳转到的地址,但它通常存储在调用堆栈或寄存器中。一些crt1实现使用exit(main(argc, argc, envp)),所以如果你正确配置链接器,你可以覆盖exit函数。 return 的参数不是地址。 在运行程序和调用main,然后当main 退出和操作系统获得返回状态之间有很多事情发生。我认为这可能是一个比你想象的更大的问题。 【参考方案1】:

当您return 0 时,您不会返回地址。您正在返回 0。当进程返回值 0 时,它被认为是正常终止。您可以返回一个非零值(最多 255),调用进程可能会将其解释为消息。

让我们用一个示例命令grep foobar fubar 来看看这个。如果文件fubar 中存在模式foobar,它将返回0(成功)。如果文件fubar 中没有foobar,它将返回1。当没有名为 fubar 的文件时,它将返回 2。 rturn 值可以在使该命令评估成功或失败原因的脚本中进行解释。

【讨论】:

操作系统以某种方式从程序中获取值 0,对吗?这个值去哪儿了? @Davlog 在调用 main 之前和之后执行特定于系统/实现的代码。 它不是地址,操作系统在进程上初始化程序/线程,当程序关闭时,程序堆栈上的最后一件事是返回值,操作系统从中获取返回值。如果你有一个特定的地址,你会遇到很多问题。 你确实返回了一个地址。当然不是地址0,而是堆栈上的地址,在启动代码调用main时被压入。 @Davlog 没有“地址”你正在返回一个值。【参考方案2】:

退出代码(最终)存储到进程控制块中,以便操作系统可以将结果值报告给其他进程。

见http://www.cs.auckland.ac.nz/compsci340s2c/lectures/lecture06.pdf

但是,return 语句并不是这样做的。您的运行时库实际上或多或少像普通函数一样调用main,获取返回值(在英特尔上,int 类型的返回值将存储在EAX 寄存器中),然后请求内核将其写入 TCB。 exit() 也调用内核来写这个 TCB 成员。

【讨论】:

exit 和从main 返回的功能远不止于此。 (当然,他们不会直接向 PCB 写入任何东西,假设操作系统有一个;他们调用一个操作系统特定的原语,返回代码负责处理所有这些。) @James:澄清实际写入是由内核在进程的请求下完成的。 是的。关键部分是,在某些时候,exit 将调用内核级原语来告诉它终止进程;这个内核级原语将使用返回码(作为参数传递给这个内核原语)以及阻止进程被调度的信息来更新 PCB(或内核编码人员决定调用的任何内容);该原语还将回收进程的所有资源,并可能记录一些会计信息。 @James:我猜所有的资源除了 TCB,它作为僵尸进程存在,直到wait 获得它。当然,关闭句柄是exit 的一个非常重要的部分。 差不多。 exit 刷新并关闭高级文件结构,但如果忘记了任何内容,系统将关闭低级文件描述符,作为处理后清理的一部分。 (我在很多很多年前实现了一个 C 运行时,exit 一点也不简单。)【参考方案3】:

main 中的 return 0; 在任何地方都可以像 return 一样工作;它 返回调用它的地方。你几时开始 一个程序,系统确实main启动它,而是在某个 进行大量初始化的启动地址,然后 类似:

exit( main(/*...*/) );

换句话说,exit 不模拟从main 的返回; 从main 返回调用exit。然后退出做了很多 关闭,在调用某些系统特定函数之前 它告诉系统停止进程(Unix 下的_exit)。

你不能自己实现exit,因为你没有办法 找到它需要的信息:函数列表 注册atexit 需要调用的,列表 具有静态生命周期的对象的析构函数等。

【讨论】:

«您不能自己实施退出» — 错误!如果是别人做的,那么你当然也可以自己做。毕竟,您甚至可以拦截对exit() 的调用并提供您自己的实现。 @VladLazarenko 由于我列举的原因,您不能自己实现exitexit 不仅仅是返回系统;它必须清理。它必须做的事情列表不是您可以访问的全局符号,并且没有外部定义的结构,因此您知道如何处理它们。 exit 与 C 运行时库的其余部分一起使用,要实现 exit,您需要 C 运行时库的源代码。 我认为重要的是要概述 atexit 它与标准库无关,但它在选择的 C++ ABI 库中实现,换句话说,它是一个不授予在那里,这是特定于平台的东西。 我可以!为什么不?你认为谁实现了你称之为的 exit() 函数,众神?至于 main() 中的 return 语句,请参见 §5.1.2.2.3 程序终止。从 C99 开始,这种情况下的返回值为 0。 @user2485710 atexit() 在 C 标准的 §7.22.4.2 中定义,并在 C++ 标准的 §18.5 中引用。它不是特定于平台的。 (当然是如何实现的。)【参考方案4】:

我认为这里的主要混淆是 main 是 C++ 程序中发生的第一件事和最后一件事。虽然它是 [1] 您程序的第一部分,但应用程序中通常有一些代码用于设置一些东西、解析命令行参数、打开/初始化标准 I/O(cincout、等)和其他类似的事情,发生在main 被调用之前。而main 本质上只是另一个函数,由 C++ 运行时功能调用,它执行“在main 之前修复问题”。

所以,当main 返回时,它会返回调用它的代码,然后清理需要清理的东西(关闭标准 I/O 通道和许多其他类似的东西),然后才真正完成通过调用一些操作系统函数来“终止这个进程”。作为“终止此进程”功能的一部分,(在大多数操作系统中)是一种向操作系统发出“成功或失败”信号的方式,以便监视应用程序的其他进程可以确定“是否一切正常”。这就是0(或1,如果你在main 中使用return 1;)最终结束的地方。

[1] 如果存在带有构造函数的静态对象是用户代码的一部分,那么这些将在main 中的任何代码之前执行[或至少在main 中属于用户代码的任何代码之前执行应用程序]被执行。

【讨论】:

【参考方案5】:

您的困惑是因为不了解return 的作用。以这个函数为例:

int add(int x, int y)

   return (x + y);

上述函数中的 return 和 main 函数末尾的 return 语句完全相同,从语言的角度来看它们的含义相同。其含义是向调用者返回一个整数。调用者从这个值中得到什么完全是另一回事,这取决于调用者调用所述函数的意图。假设我可以调用add(7, 9); 来增加两个 GPA 成绩,而另一个程序员可能会调用它来查找几个银行账户中所有资金的总和。

现在main 被视为一个特殊函数,因为它是操作系统(或者更具体地说是它的加载器)调用成为您的程序的第一个函数。程序完成后,main 返回的任何内容都可能意味着基于操作系统语义的任何内容。该值与任何内存地址无关。

旁白:根据标准,在 C++(和 C99 以上)中,return 0; 语句可以省略以表示程序成功终止。

【讨论】:

这取决于 C 的哪个版本,不是吗? @BenVoigt:你的意思是在 main 的末尾省略了return 0; 您也可以在 C 中安全地省略 mains return 0;`。在 C99 中。 标准要求实现将0EXIT_SUCCESS 识别为成功。在旧 DEC OS 等系统上,奇数表示成功,C 运行时必须将 0 重新映射为奇数。 @legends2k:是的,这是您回答中对 C 的唯一引用,这也是我在评论的内容。我发现这条规则“到达终止 main 函数的 返回值 0。”【参考方案6】:

如果我的理解是正确的,将会有一个 SIGCHLD 信号在退出时发送到包含返回值的主 shell...这应该在 PCB 被内核破坏时发生...

但是如果您想在退出代码时连接某些功能,您可以根据 POSIX 实现在 atexit() 处注册一个处理程序..

我认为您不能修改返回值在用户级别的传播方式,因为程序的控制权在另一个进程(您无权访问)中到达 PC。

【讨论】:

PCB 在被wait 收割之前不会被内核破坏。【参考方案7】:

如果您的 C++ abi 库实现符号 __cxa_atexit,您可以使用 atexit

AFAIK 该语言并没有真正提供其他安全方式来在程序停止执行时执行用户定义的操作。

【讨论】:

【参考方案8】:

当你有一个function 时,它就有一个类型。它可以是intvoid 或其他。如果函数不是 void,那么它必须返回一个值。在我们的例子中,mainreturn 值是int,通常是return 代码。按照惯例,如果为0,则没有错误,其他值为错误码。

【讨论】:

以上是关于C++ 在 main() 结束时返回 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

每天一个编程小技巧C++ return:使函数立即结束!

每天一个编程小技巧C++ return:使函数立即结束!

技术杂记

main函数

视频播放结束后如何返回 tvOS 中的 Main.storyboard?

C++并发与多线程 2_线程启动结束,创建线程多种方法,join,detach