直到今天,我对函数和返回语句概念的理解是这样的:
当控件到达函数末尾时,控件将返回给调用者(函数)。无论函数是否有
return
语句,都会发生这种情况。
ISO C on exit()
在阅读关于终止C程序的文章时,我看到了ISO C(7.22.4.4.6)-的一条声明
exit函数无法返回到其调用方。
这句话与我以前的理解相矛盾。
ISO C退货声明
因此,我查看了ISO C对return
语句的注释(6.8.6.4),发现:
- 带有表达式的返回语句不应出现在返回类型为void的函数中。没有表达式的返回语句只能出现在返回类型为void的函数中
- return语句终止当前函数的执行,并将控制权返回给调用方。函数可以有任意数量的返回语句
我的新结论
- "return"语句使主机环境强制将控制权返回给调用者(函数)
- 如果函数返回类型为的
void
,如果它包含return
语句,则主机环境必须将控制权返回给调用方(函数)。否则(即,如果return
语句不存在),则主机环境可以将控制权返回给调用者- 默认情况下,许多实现都选择将控制权返回给调用方函数,即使被调用方函数没有
return
语句,但exit()
的情况除外(此异常也可能扩展到其他一些函数)
我的结论正确吗
您的函数在程序中。它们不是主机环境的一部分。主机环境在您的程序之外。在普通的通用多用户系统中,主机环境是操作系统(包括用于执行程序的命令行shell)。
return
语句返回到程序内部的调用函数。流向函数的关闭}
的程序控制将控制返回到调用函数。调用exit
不会返回到程序中的函数;它向操作系统发出终止程序的请求。(但是,在发出此最终请求之前,exit
可能会执行各种清理工作并调用退出处理程序,因此程序中的某些功能可能仍会在程序终止之前执行。)
当然,您引用的标准都是正确的,而且不矛盾。
exit()
但是exit()
函数的描述与return语句的作用无关。这主要是因为它不包含一个,或者至少从未达到一个。它也永远不会走到尽头。相反,它指示操作系统(如Linux或Windows)完全停止执行程序,而程序仍在执行退出功能。这就是exit()
从不返回的原因:它只是简单地停止并与程序的其余部分一起从内存中删除。它不仅没有回来;没有什么可返回的了。
从函数调用和返回
函数调用本质上是跳转到不同的机器代码指令,再加上一些细节。例如,我们从中跳转的地址被存储起来,这样我们就知道函数结束后在哪里继续,参数被存储在某个地方,这样被调用的函数就可以访问它们。从函数返回同样是跳转到存储的返回地址,再加上一些细节,比如将返回值(如果有的话)放在调用者可以访问的地方。到达函数的末尾完全等同于点击返回语句,没有函数上的区别。
代码";呼叫";函数及其返回的代码完全由编译器生成。不涉及操作系统。该代码是编译器生成的二进制文件的一部分。
使用操作系统设施
相比之下,终止程序是每个操作系统向程序提供的基本服务之一。执行此操作的代码不是程序的一部分,而是Linux或Windows等操作系统的一部分。想要利用这种操作系统服务的程序必须进行系统调用2。Windows下的一个这样的调用可能是ExitProcess()
,它可能在某个时候被C标准库的Windowsexit()
实现所调用。因为这将导致Windows停止当前进程,因此exit()
中的代码之后将永远不会执行,包括任何将控制权返回给调用函数的代码,例如main()
。
C程序在操作系统之间可移植的原因之一是包装器保护C程序不受任何给定操作系统的特殊性的影响:标准C库。
如果没有标准库,用于Windows的C程序将调用例如ReadFile()
或ExitProcess()
,而Posix程序将调用read()
或_exit()
。将一个程序从一个操作系统移植到另一个操作系会对源代码进行必要的更改。相比之下仅使用标准库调用fread()
和exit()
的C程序(该页面包含Posix平台特定_exit()
函数的文档以及标准C库函数exit()
)将在任何具有带标准库的C编译器的平台上重新编译:对新操作系统的适应只需要一次——当库被移植时——然后可用于所有程序。
您的问题
现在我们可以回答您的问题了。
-
否,
return
语句不会引起与操作系统的任何交互。一切都停留在运行的进程中,没有任何系统资源被使用或释放3 -
由于
return
语句或由于到达函数末尾而返回是完全等效的。生成的代码完全等效。在这两种情况下,都必须将控制流返回到调用函数。(exit()
函数不返回的原因是它在到达结束或返回语句之前终止了进程。如果它到达了其中一个,它将返回,调用方将恢复执行。) -
上一段对此作出了答复;只是为了澄清:当函数结束时,一致性实现不能在返回或不返回调用者之间自由选择;
exit()
函数永远不会结束。
1值得注意的是,操作系统本身已经提供了一个标准化层:每个使用Windows API的程序都可以使用ReadFile()
,而与特定机器上使用的特定文件系统和I/O芯片组无关。C标准库是在这些抽象层之上的一个抽象/标准化层。
2我使用";系统调用";这里有点松散地称为";本机OS API中的函数";。
3除非函数在单独的任务中执行,否则这完全是另一回事。