Poedu_C语言_Lesson21_20160924_函数1

1.C语言被称为过程式语言:把执行过程分解为一个个的函数

=>好处在于:1)方便工程的管理

    2)方便多次进行调用

=>注:在程序的编写中,要形成“功能即封装”的意识,尽量做到使每个封装的函数的功能单一化,对于程序整体的管理以及代码的可读性方面都有非常大的好处。

2.将反复使用的算法代码抽象到一个函数当中,需要的数据可由外部参数进行传递

=>函数往往是可以实现一种算法的抽象,举一个很简单的例子,比如下面这个程序:


这个函数的功能很简单,就是比较两个数值的大小,如果第一个数大于第二个数,则返回true。而待比较的两个数值是由我们外部进行传递的。当我们程序的某个地方需要使用的时候,就可以对函数进行调用,一行代码就搞定了。

传递的参数因我们的设定也会有分别:

1)是像上面的程序,通过数值的复制进行调用的。比如下面这个小程序:


在程序的main函数中,我们队BigNum进行了调用,传入了两个参数(都是int型的,与封装函数的参数的类型要保持一致)。这种传递称为值传递,我们从汇编看一下为什么这么说:

这是我从反汇编中截取的部分内容。首先,可以看到,编译器将14h(h后缀,是十六进制的,十进制就是20,下面的数值同样是十六进制的)通过mov指令传入numfirst的地址中,numSecond的赋值也同样是这样,然后到了BigNum函数,第一步操作是将numSecond的地址中存放的值复制给eax,再将eax压入栈中。对于numFirst的操作也是这样的,区别就是它所保存的地址不同。

重要的一点,我们可以看到,BigNum操作的数值,是由我们传入参数的复制版本,并不是本身,所以,如果在BigNum里面对numFirst和numSecond进行改写,有效果么?相信你肯定看过这方面的例子,那就是不行。为什么?因为函数操作的是复制版本啊,并不是本身。如果进行了改写操作,那么改写的只是副本,对于本体没有影响。

2)传递的参数是地址,我们将上面的程序改写一下:

这段代码与上段代码不一样的是,BigNum里的参数多了一个“*”,这个“*”代表所传递的参数是指针。而在进行调用的时候,要在numFirst和numSecond之前加一个“&”,表示取地址。也就是将这两个数值的地址传递给BigNum,再由它进行使用。当传入BigNum里面后,BigNum再进行取值操作(*numFirst)。所以说,此时BigNum里面操作的是numFirst与numSecond的实体,如果进行了改写,那么它在main函数里也会有变化,稍后会进行结果输出,到时候就能看到是否真的是这样的。在此之前,让我们看一下反汇编里是什么样的情况:

前面的赋值操作和上一个程序是一样的,不同的地方在于传递的参数。第一个程序是通过mov指令将传入的值复制,再进行压栈操作。而这个程序中,用的是lea(取地址指令),直接是将传入的地址压入栈中,供BigNum调用。现在就让我们看一下结果,如果numFirst的值变为了30,那么就可以印证我们的猜想:

numFirst=30,结果和我们猜想的一样。

那么哪种传入方式更好呢?我认为,首先要看你是否有改变参数本体的需求。其次,要看你参数的数据类型,因为指针的大小都是4byte,如果你的参数是结构体等类型,通过复制值的方式进行传递,那么很明显,所耗费的时间是传入指针的数倍。

3.在进行函数封装的时候,需要注意三个要素:

1.名称:唯一性,不要出现两个函数名相同的情况

2.参数:可以是多种多样的,由你自己确定需要怎样的函数,要注意的是,不要传入多余的参数,因为参数是通过栈进行传递的,如果传递的多了,难免会影响效率。

3.返回值:每一个函数都要有返回值。或许你会说,void类型的就没有返回值,但是,实际上它也是有的,由编译器帮你做了这件事情。如果有办法,尽量做一个返回,当然这个返回值应当是有意义的,不要为了返回而返回。

4.每一个函数都拥有一个独立的栈。这一点在前面的函数调用有讲到,此处不再赘述。








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值