大家好,今天小编来为大家解答c语言return返回值给谁这个问题,c语言return的用法详解很多人还不知道,现在让我们一起来看看吧!
既然C语言函数的局部变量会被释放,那为什么函数还可以把它return返回呢
看了底下兄弟的答复,只能说答对了一半。
真正的原因在于ABI(应用程序二进制接口)。
ABI定义了与系统交互的细节:如数据类型、大小和对齐;调用约定(控制函数的参数的传递方向、可变长度处理、堆栈清理主体以及如何接受返回值等);系统调用的编码和一个应用如何向操作系统进行系统调用;以及在一个完整的操作系统ABI中,目标文件的二进制格式、程序库等等。一个完整的ABI,像Intel二进制兼容标准(iBCS),允许支持它的操作系统上的程序不经修改在其他支持此ABI的操作体统上运行。
其他的ABI标准化细节还包括C++名称修饰,和同一个平台上的编译器之间的调用约定,但是不包括跨平台的兼容性。
至于底下兄弟所说的EAX保存返回值,这个只是X86的ABI规范,在PowerPC等其他CPU架构平台,实现是不一样的!——PowerPC下,返回值是保存在R3寄存器中的
c语言return语句什么时候用
当你定义函数的时候才要用,有些函数有返回值,也就是调用一个函数之后,该函数返回一个值给你。
如intfun(inta)这个函数就要用return,而且return后面跟的变量或字面常量应该是整形才对,如果是不能自动转换成整形的数据如double型的,系统就会报错,但是如果return一个short型的变量,该变量会被自动转化为int型变量。
总之,return后面跟的变量或者表达式结果的类型要与函数的类型一致。
现在知道为什么intmain()最后要return0;了吧(其实为什么是0我也不知道,应该有什么含义吧)
函数类型之中,有一个类型叫做空类型,也就是void
如voidfun(inta)
这个函数里面可以用return(后面不跟数据),也可以把return语句省略。这时函数调用到最后一个右大括号时结束。
一般用void的话就是没有返回值和不需要返回值的了,如调用一个输出函数,这个函数就没必要返回了,事实上这个函数只管输出就好了,也没有什么值要返回的,另一种是用指针传址的时候,因为你传的是地址,函数根据你的地址直接对数据进行操作了,这是就不需要返回值了。
因为对数据的操作在函数里已经进行了(返回值的作用一般是赋值或者作为参数的赋值的话可以对变量直接操作,也就是用指针操作,也可以把返回值赋值给变量)
另外,return语句还有另一个功能就是结束函数调用,有时候,当某种情况发生的时候(或者说满足一定情况的时候),必须结束程序,如当你申请动态空间失败的时候,由于这是一个严重错误,所以必须强制终止程序,这时就可以用return语句来提前结束运行。
C语言中,函数的返回值返回到main函数后,赋予给一个变量,之后就被回收了吗还有哪些编程细节需要注意
根据所用编译器和CPU的不同,以及返回值数据类型的不同,C语言中的函数返回值可能通过寄存器传递,也可能通过栈传递。对大多数CPU和编译器来说,出于性能考虑,能使用寄存器传递的,尽量使用寄存器传递,只有当寄存器不够用的时候,才会通过栈传递。
针对这两种情况,我分别举个x64+GCC环境下的例子来说明。
通过寄存器传递返回值如下图中的一段简单的代码,返回值是一个有符号整数类型
我们看下x64/GCC下面对应的汇编代码:
test函数中的
1129:mov$0x2,%eax
便是把返回值2存放到eax寄存器中。而main函数中的
113d:callq1125<test>
1142:mov%eax,-0x4(%rbp)
则先调用test函数,然后把返回值从eax中取出,并存放到rbp-4的地址处,也就是赋值给局部变量a。
通过栈传递返回值下面这个例子中,test()函数返回一个结构体structresult。(注:这里只是为了演示用栈传递返回值,实际项目中不建议函数直接返回结构体,可以用结构体指针代替)
(这个例子第一眼看上去会有些许复杂,千万不要懵逼,汇编代码不是洪水猛兽,掌握一些基本的汇编代码对修炼内功、调试问题都是大有裨益的:)
在x64/GCC环境下的汇编代码如下:
先看main()函数:
我们先看main()函数中调用test()的几条指令:
ret=test();
11dd:lea-0x50(%rbp),%rax
11e1:mov%rax,%rdi
11e4:mov$0x0,%eax
11e9:callq1135<test>
11dd和11e1两条指令的作用是把栈地址rbp-0x50存放到rdi寄存器中,我们暂且不去管这个地址是用来做什么的,等看了test()函数之后自然就会明白。后面两条指令是把eax清零,然后调用test()函数。
test()函数的汇编代码如下:
test()的汇编看起来是不是有点复杂呢?不要紧张,其实做的事情很简单,就是给局部变量r分配栈空间,然后对它进行初始化,然后把r的值存放到一个内存地址当中,最后把这个内存地址放到rax寄存器中,并返回出去。我们仔细分析一下:
1139:mov%rdi,-0x28(%rbp)
这条指令是把rdi寄存器的值存放到栈空间rbp-0x28的地址处。还记得rdi寄存器中存放的是什么吗?回想一下,在main()函数调用test()函数之前,是不是把一个地址存放到rdi寄存器中了呢?忘了的话,再去看一下。我们先不管这个值用来做什么,只要记得,test()函数把main()函数传递过来的一个值存放到了一个栈地址当中。
接下来的这几条指令,就是对局部变量r进行初始化:
structresultr={1,2,3,4};
113d:movq$0x1,-0x20(%rbp)
1145:movq$0x2,-0x18(%rbp)
114d:movq$0x3,-0x10(%rbp)
1155:movq$0x4,-0x8(%rbp)
下面就要把r的值返回出去了,我们来看看编译器是怎么做的,先看这几条指令:
returnr;
115d:mov-0x28(%rbp),%rcx
1161:mov-0x20(%rbp),%rax
1165:mov-0x18(%rbp),%rdx
1169:mov%rax,(%rcx)
116c:mov%rdx,0x8(%rcx)
115d这条指令,是把栈中rbp-0x28处的值放到rcx寄存器中,还记得这个地址存放的值是什么吗?对了,就是test()入口处从rdi中取出来的那个值,也就是main()函数通过rdi寄存器传递给test()的一个值。然后,1161和1169两条指令把r.a值存放到rcx寄存器指向的地址处,1165和116c两条指令把r.b的值存放到rcx寄存器指向的地址再偏移8的位置处。
现在我们再来回过头想一下,main()函数通过rdi寄存器传递给test()函数的那个值是用来做什么的呢?对了,那个值其实就是存放test()函数返回值的那块内存的地址。
那么记下来的几条指令就比较容易理解了:
1170:mov-0x10(%rbp),%rax
1174:mov-0x8(%rbp),%rdx
1178:mov%rax,0x10(%rcx)
117c:mov%rdx,0x18(%rcx)
1170和1178把r.c存放到rcx+0x10地址处,1174和117c把r.d存放到rcx+0x18地址处。
到这里为止,test()函数已经把局部变量structresultr的所有字段的值全部存放到main()函数通过rdi寄存器传递给test()的那个内存地址中。
最后,看一下剩下的几条指令:
1180:mov-0x28(%rbp),%rax
1184:pop%rbp
1185:retq
1180指令把rbp-0x28处的值rax中,也就是把存放返回值的那块内存的地址,存放到rax寄存器中,最后返回出去。
到这里,是不是清晰多了呢?我们再来总结一下这个过程:
main()函数把一个栈空间中的地址rbp-0x30通过rdi寄存器传递给test()函数test()函数从rdi寄存器中取得这个地址,然后把要返回的值存放到这个地址指向的内存中test()把这个地址存放到rax寄存器中,并返回给main()函数掌握一定汇编知识的重要性可能对于很多童鞋来说,汇编语言比较晦涩难懂,难以掌握。确实,作为一个最为接近机器语言的编程语言来说,汇编确实比较晦涩,除了一些做底层系统软件的童鞋外,日常工作中直接用汇编写代码的机会确实不多,但是,这并不意味着掌握汇编语言就毫无用处。
掌握一定的汇编知识,会对整个计算机的原理和体系结构有更深入的理解,很多东西都能够知其然并知其所以然。尤其那些对底层系统软件感兴趣的童鞋,如BIOS/bootloader、OS内核、设备驱动、编译器、虚拟机等,汇编语言更是必须要掌握的。有些做上层应用的童鞋,如前端开发等,平时用到汇编的机会不多,但是在调试一些问题的时候,如果能够了解一些汇编知识,就会如虎添翼,事半功倍。
总之,不管所用的开发语言是C/C++还是Java、Python、PHP、Javascript,不管是做系统软件开发,还是做前端开发,只要是有志于干程序员这一行当的,掌握一定的汇编,对完善自己的技术知识体系,增强自己调试问题的能力,和对计算机体系结构的理解都大有裨益。
思考题能坚持读到这里,我想你已经基本清楚C语言的函数返回值是怎么传递的了。
那么,不妨思考一下,C语言的函数参数又是怎么传递的呢???欢迎留言,或者私信讨论,要是有人感兴趣,我可以写篇文章介绍一下。
最后,对这个问题有不清楚的地方,欢迎留言讨论。也欢迎关注,我计划在接下来的一段时间,更新一些偏底层的东西,如Linuxkernel(e.g.memorymanagement、processmanagement、scheduling、timekeeping,etc.)、KVM/Qemuvirtualization、compiler、debugger等,有兴趣的童鞋欢迎关注,互相交流学习。
c语言return后面是o还是0
c语言return后面是0,是数字0;
C语言中及许多的编程语言中,返回值为0表示正常退出,正常返回;当然在一些具体函数中,代表返回数字0;另外,return后面在具体函数中可以返回任意数值;在主函数即main函数中,return0的写法一般是固定的,在其他函数中可以视函数返回值的需要而定。
c语言return后面的参数
return后面的参数是函数的返回值,是函数的运算结果。
OK,关于c语言return返回值给谁和c语言return的用法详解的内容到此结束了,希望对大家有所帮助。