首页 > 其他分享 >函数原型以及相关知识

函数原型以及相关知识

时间:2022-11-06 22:14:22浏览次数:36  
标签:调用 函数 知识 主调 原型 参数 声明

先说结论:ANSI C以及之前的C语言可以不声明(declare)函数原型(prototype)而直接调用(call)函数,但是C99以及之后的语言标准要求先声明函数原型。

但是各大编译器可以有自己的实现,如GCC(GNU C Comlier,Dev-C++所附带的的MinGW的G就是GNU)可以由定义式(definition)自动获得原型声明,完全正确,但必须在调用该函数之前。若函数定义在调用者的后面,则其会隐式声明为int(int),一旦其定义式与它不一样则报错(如图foo函数在GCC下正常,而bar函数报错)。image

以下给出自己查阅资料的结果,最后给出参考资料。

C语言的函数经编译后成为目标码,在运行期(Runtime)时在内存中有它的地址(甚至可以被函数指针“指涉”,refer to)。
函数调用(call)时,主调函数(caller)把实参计算后复制一份压入函数栈(经过优化甚至将前几个参数传入寄存器eax、ebx等),然后,被调用的函数按照参数列表(parameter list)取得参数、进行操作并在遇到return或最后一个右花括号时执行ret汇编指令,把返回值(如有需要)转为声明的类型后返回给主调函数。

这就解释了声明原型或者不声明、乃至无参函数传入参数甚至传入可变参数的道理:
声明原型是告诉主调函数它应该把参数转为何类型、压到哪个地址;不声明原型则都为int、按默认顺序复制到对应地址。
这样主调函数不必操心它调用的函数如何实现,它只需按照原型压栈、等待其返回并取得返回值即可。
这也解释了C语言不区分递归和非递归函数的道理:它根本不必区分,二者本质上没有区别。即使该函数没有定义完全而其内部却要调用自己时,该调用语句也只是被编译为压栈、跳转等等寥寥几行汇编码,而不操心被调用函数干了什么——毕竟已经把活交给被调用的函数了,主调函数就不必操心其实现了。
这也解释了我们常把main定义为void,而操作系统总是给它int argc和char *argv[]两“个”参数,但是没有发生问题。
根据这个道理我们甚至可以自己用神奇的方法(比如stdargs.h里面的va_list等“宏”,macro)取得传入的值,这样就实现了可变参数。

这体现了C语言的哲学以及其“底层”的特点,这种哲学也运用在别处。
如编写链表或者二叉树等等数据结构时,代表每个节点的类型的结构体类型(struct-type)尚未声明完全时即可在其内部声明指向该结构体类型的指针。因为指针仅仅指涉(refer to)某事物,而不操心该事物内部结构如何;甚至不同字长的机器上指针变量的长度(用sizeof(void*)即可查看)也不一样。这跟函数调用时caller只压栈和取返回值,而不关心被调用的函数如何实现是一致的。

怎样,每次调用函数的时候居然做了这么多事情,很神奇吧?
还有inline, __cdecl, __stdcall, _Noreturn等等修饰符用于函数定义或声明,其功能更加纷繁复杂,留待想要深刻学习的同学去探索。

附参考,书名“Modern C”,作者Gens Gustedt,中文版有售。

image
image
image

标签:调用,函数,知识,主调,原型,参数,声明
From: https://www.cnblogs.com/quanqiutong-u1/p/16864316.html

相关文章

  • 函数高级
    1.函数的默认参数:为函数的形参列表赋予默认值语法:  即不传值,函数就默认使用自己的数据。例子:注意事项:1)若函数某个位置已经有默认参数,那么从这个位置开始往后们都......
  • c语言学习--静态函数
    静态函数 #include<stdio.h>//这是静态函数,静态函数只能在当前文件调用,其他文件下面的函数是没法调用到这个函数的staticvoidfun1(){printf("helloworld"......
  • Angular 14 inject 函数使用过程中的一些注意事项
    inject函数只能用于构造器阶段,这意味着其只能在构造器函数作用域(constructorfunctionscope)和字段初始化器(fieldinitializers)中使用。下列代码会遇到运行时错误(runtim......
  • Angular 14 新的 inject 函数介绍
    Angular14提供了一些非常有趣的特性:类型化表单(typedforms)、独立组件(standalonecomponents),以及本文将要介绍的内容,即在所谓的构造器阶段(constructorphase)使用inj......
  • EXCEL用DB函数计算商品房4年后每年的折旧额
    DB函数主要是用于计算通过固定余额递减法来计算某资产在一定时间内的折旧值,其语法结构为:DB(cost,salvage,life,period,month),各参数的含义如下:cost参数:该参数用于指定资产原值......
  • c原因学习---指针作为函数的形参
     指针作为函数的形参,可以改变实参的值。#include<stdio.h>//交换两个变量的值intswap(intx,inty){intk=y;y=x;x=k;printf("xi......
  • 【模板】Z 函数(扩展 KMP)
    postedon2022-08-0823:29:53|under模板|source#include<cstdio>#include<cstring>#include<algorithm>usingnamespacestd;typedeflonglongLL;intn,......
  • 服务框架基础知识总结
    转载:https://www.cnblogs.com/imyalost/p/10274797.html参考:《京东基础架构建设之路》 要组成一个基本的通信服务框架,最起码需要这三部分:统一的RPC框架、服务注册中心......
  • [代码审计]信呼协同办公系统2.2存在文件上传配合云处理函数组合拳RCE
    文章目录​​写在前面​​分析​​​​脚本​​写在前面本次强网杯决赛的一个题,还是蛮有意思的,代码可以在github拿到​​​https://github.com/rainrocka/xinhu​​分析首......
  • 指针+函数解决问题
    问题:交换两个整形的数值#include<stdio.h>voidswap(int*pa, int*pb){inttmp=*pa;*pa=*pb;*pb=tmp;}int main(){int a=45;int b=86;printf("a=%db=%d\n",a,b);sw......