读《高质量C/C++》 – 函数

对于函数大家肯定不陌生,所以什么是函数,函数干什么的,实参以及型参之类的话题就不用提及了,我主要想知道:程序是怎么调用函数的?实参型参是怎样联系的?函数有哪些需要注意的?
首先,程序是怎样调用函数。我们对函数的调用主要分为调用自定义函数以及库函数,那当我们调用函数的时候是怎样的一个具体流程喃?我们先以自定义函数为例:
// lib.h+lib.c
#ifndef __LIB_H__
#define __LIB_H__
//#include <stdio.h>
void user_fun2( void );
void user_fun( void );
#endif
#include "lib.h"
#include <stdio.h>
void user_fun(void)
{
  printf("call user1_fun,fun2 add:%p\r\n",user_fun2);
}
void user_fun2(void)
{
printf("call user2_fun,fun1 add:%p\r\n",&user_fun);
}
// test.c
#include <stdio.h>
#include "lib.h"
static const int FUN_ADD1 = 1000;
static const int FUN_ADD2 = 1000;
static const char* fun1_str = "call functon1Test()\r\n";
static const char* fun2_str = "call functon2Test()\r\n";
static const char* sint1_str = "static const int1:%p\r\n";
static const char* sint2_str = "static const int2:%p\r\n";
static const char* int1_str = "int1:%p\r\n";
static const char* int2_str = "int2:%p\r\n";
static const char* fun1add_str = "function1Test:%p\r\n";
static const char* fun2add_str = "function2Test:%p\r\n";
static const char* userfun1add_str = "user1_fun:%p\r\n";
static const char* userfun2add_str = "user2_fun:%p\r\n";
void functionTest(void)
{
printf(fun1_str);
}
void functionTest2(void)
{
printf(fun2_str);
}
int main( int argc, char **argv)
{
int num1 = 100;
int num2 = 100;
void (*fun1_addr)() = &functionTest;
void (*fun2_addr)() = &functionTest2;
void (*ufun1_addr)() = &user_fun;
void (*ufun2_addr)() = &user_fun2;
 
printf( sint1_str,&FUN_ADD1 );
printf( sint2_str,&FUN_ADD2 );
printf( int1_str,&num1 );
printf( int2_str,&num2 );
printf( fun1add_str,&functionTest );
printf( fun2add_str,&functionTest2 );
printf( userfun1add_str,&user_fun ); 
printf( userfun2add_str,&user_fun2 );
printf( fun1add_str,fun1_addr );
printf( fun2add_str,fun2_addr );
printf( userfun1add_str,ufun1_addr );
printf( userfun2add_str,ufun2_addr );
printf("fun1 size:%d,fun2 size:%d,ufun1 size:%d,ufun2 size:%d\r\n",sizeof(&functionTest),sizeof(&functionTest2),sizeof(&user_fun),sizeof(&user_fun2));
functionTest();
functionTest2();
user_fun();
user_fun2();
ufun1_addr();
ufun2_addr();
return 0;
}
// 结果:
static const int1:0x804883c // 静态区域部分地址
static const int2:0x8048840     // 静态区域部分地址
int1:0xbfdc39d0 // 堆栈区域部分地址
int2:0xbfdc39cc // 堆栈区域部分地址
function1Test:0x8048548 // 函数地址和上面静态区域地址临近,应该是被分配在静态区域
function2Test:0x8048552 // 函数地址和上面静态区域地址临近,应该是被分配在静态区域
user1_fun:0x8048504 // 自定义函数地址,临近同文件函数地址,同样分配在静态区域
user2_fun:0x8048525 // 自定义函数地址,临近同文件函数地址,同样分配在静态区域
function1Test:0x8048548
function2Test:0x8048552
user1_fun:0x8048504
user2_fun:0x8048525
fun1 size:4,fun2 size:4,ufun1 size:4,ufun2 size:4
call user1_fun,fun2 add:0x8048525 // 不动作用域调用同一地址( 此次调用是发生在 lib.c )
call user2_fun,fun1 add:0x8048504 // 不动作用域调用同一地址( 此次调用是发生在 lib.c )
call user1_fun,fun2 add:0x8048525 // 不动作用域调用同一地址( 此次调用是发生在 lib.c )
call user2_fun,fun1 add:0x8048504 // 不动作用域调用同一地址( 此次调用是发生在 lib.c )
// 结果分析:
从以上的实验结果,得出一切归于地址,编译器会为调用函数分配一个静态区域的地址,所有调用将会在该区域进行。《高质量C/C++》中提到对静态库和动态库的使用,其中在使用静态库的时候只有当调用到库中的函数时候,连接器才将代码段连接到程序中, 而动态库在运行时需要拷贝到当前的运行环境的相应目录中。

其次,再来实验一下实参和型参之间的联系,在书中提到调用过程中使用实参来初始化型参,测试代码如下: 

class Persion
{
public:
Persion( int age,char *name ):m_age(age),m_name(name),m_namelen(0)
printf("new persion\r\n");
};
Persion( const Persion &p )
{
m_age = p.m_age;
m_namelen = strlen( p.m_name );
m_name = new char[ m_namelen+1 ];
strcpy_s( m_name,m_namelen+1,p.m_name );
printf("call copy function \r\n");
};
Persion& operator=( const Persion &p )
{
};
~Persion()
if( m_namelen != 0 )
{
delete[] m_name;
m_name = NULL;
m_namelen = 0;
}
printf("destory persion\r\n");
};
int  m_age;
char *m_name;
size_t m_namelen;
};
void functionV( const Persion p )
{
printf("%s is %d \r\n",p.m_name,p.m_age );
}
void functionR( const Persion &p )
{
printf("%s is %d \r\n",p.m_name,p.m_age );
}
int _tmain(int argc, _TCHAR* argv[])
{
Persion chen( 27,"chen");
Persion *yang = new Persion( 27,"yang" );
printf("call value function:\r\n");
functionV( chen );
printf("call ref function:\r\n");
functionR( *yang );
delete yang;
return 0;
}
运行结果如下:
new persion
new persion
call value function: // 当以值的方式传递的时候
call copy function // 这里调用了拷贝构造函数,说明参数进行了一个初始化过程
chen is 27
destory persion
call ref function:
yang is 27
destory persion
destory persion
请按任意键继续. . .
分析:
由测试可以得出结论,正如书中所说,实参是初始化形参,而且如果是以值方式传递,会有一个初始化过程。

 

总结:被调用的函数最终是以地址的形式出现在静态区域,而函数调用的时候实参是用来初始化形参的,如果形参是值类型会有一个初始化过程。
PS:东西不多,也不值得一提,希望大家多多指点,相互交流。

原文链接: https://www.cnblogs.com/CHENYO/archive/2012/08/19/2646832.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

    读《高质量C/C++》 - 函数

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/60087

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月9日 上午9:20
下一篇 2023年2月9日 上午9:21

相关推荐