[ 随手记 1 ] C/C++宏,普通函数,内联函数
函数定义
C 语言中的函数定义的一般形式如下:
return_type function_name( parameter list )
{
body of the function
}
在 C 语言中,函数由一个函数头和一个函数主体组成。下面列出一个函数的所有组成部分:
- 返回类型:一个函数可以返回一个值。return_type 是函数返回的值的数据类型。有些函数执行所需的操作而不返回值,在这种情况下,return_type 是关键字 void。
- 函数名称:这是函数的实际名称。函数名和参数列表一起构成了函数签名。
- 参数:参数就像是占位符。当函数被调用时,您向参数传递一个值,这个值被称为实际参数。参数列表包括函数参数的类型、顺序、数量。参数是可选的,也就是说,函数可能不包含参数。
- 函数主体:函数主体包含一组定义函数执行任务的语句。
函数参数
如果函数要使用参数,则必须声明接受参数值的变量。这些变量称为函数的形式参数。
形式参数就像函数内的其他局部变量,在进入函数时被创建,退出函数时被销毁。
当调用函数时,有两种向函数传递参数的方式:
| 调用类型 | 描述 |
|---|---|
| 传值调用 | 该方法把参数的实际值复制给函数的形式参数。在这种情况下,修改函数内的形式参数不会影响实际参数。 |
| 引用调用 | 通过指针传递方式,形参为指向实参地址的指针,当对形参的指向操作时,就相当于对实参本身进行的操作。 |
默认情况下,C 使用传值调用来传递参数。一般来说,这意味着函数内的代码不能改变用于调用函数的实际参数。
===============================================================
内联函数的执行过程与带参数宏定义很相似,但参数的处理不同。带参数的宏定义并不对参数进行运算,而是直接替换;内联函数首先是函数,这就意味着函数的很多性质都适用于内联函数,即内联函数先把参数表达式进行运算求值,然后把表达式的值传递给形式参数。
内联函数与带参数宏定义的另一个区别是,内联函数的参数类型和返回值类型在声明中都有明确的指定;而带参数宏定义的参数没有类型的概念,只有在宏展开以后,才由编译器检查语法,这就存在很多的安全隐患。
使用内联函数时,应注意以下问题:
1.=====================================================================
1)内联函数的定义性声明应该出现在对该函数的第一次调用之前。
2)内联函数首先是函数,函数的很多性质都适用于内联函数,如内联函数可以重载。
3)在内联函数中不允许使用循环语句和switch结果,带有异常接口声明的函数也不能声明为内联函数。
先说宏和函数的区别:
1. 宏做的是简单的字符串替换(注意是字符串的替换,不是其他类型参数的替换),而函数的参数的传递,参数是有数据类型的,可以是各种各样的类型.
2. 宏的参数替换是不经计算而直接处理的,而函数调用是将实参的值传递给形参,既然说是值,自然是计算得来的.
3. 宏在编译之前进行,即先用宏体替换宏名,然后再编译的,而函数显然是编译之后,在执行时,才调用的.因此,宏占用的是编译的时间,而函数占用的是执行时的时间.
4. 宏的参数是不占内存空间的,因为只是做字符串的替换,而函数调用时的参数传递则是具体变量之间的信息传递,形参作为函数的局部变量,显然是占用内存的.
5. 函数的调用是需要付出一定的时空开销的,因为系统在调用函数时,要保留现场,然后转入被调用函数去执行,调用完,再返回主调函数,此时再恢复现场,这些操作,显然在宏中是没有的.
2.======================================================
现在来看内联函数:
所谓"内联函数"就是将很简单的函数"内嵌"到调用他的程序代码中,只样做的目的是为了避免上面说到的第5点,目的旨在节约下原本函数调用时的时空开销.
但必须注意的是:作为内联函数,函数体必须十分简单,不能含有循环、条件、选择等复杂的结构,否则就不能做为内联函数了。事实上,即便你没有指定函数为内
联函数,有的编译系统也会自动将很简单的函数作为内联函数处理;而对于复杂的函数,即便你指定他为内联函数,系统也不会理会的。
下面我们来介绍一下内联函数的用法。
内联函数必须是和函数体申明在一起,才有效。像这样的申明
Inline Tablefunction(int I)是没有效果的,编译器只是把函数作为普通的函
数申明,我们必须定义函数体。
Inline tablefunction(int I) {return I*I};
这样我们才算定义了一个内联函数。我们可以把它作为一般的函数一样调用。但是执行速度确比一般函数的执行速度要快。
我们也可以将定义在类的外部的函数定义为内联函数,比如:
Class TableClass{
Private:
Int I,j;
Public:
Int add() { return I+j;};
Inline int dec() { return I-j;}
Int GetNum();
}
inline int tableclass::GetNum(){
return I;
}
上面申明的三个函数都是内联函数。在C++中,在类的内部定义了函数体的
函数,被默认为是内联函数。而不管你是否有inline关键字。
3.===================================================
下面我们再来说说内联函数与宏的区别。很多的资料上,在谈到内联函数时就说,内联函数和宏很类似,但是类似归类似,毕竟我们不能把这两者互换使用。
这两者的相似之处在于执行时编译器对其的处理,会将其代码展开,执行完后继续下面的处理。不同之处在于宏是简单的文本替换,它不能返回值,也没有一般函数参数的概念;而内联函数则具备了普通函数的特征,如参数列表,返回值等。下面我们举个例子说明:
1.#define COUNT(X)(X * X) // 一个计算乘积的宏
2.inline int count(int x){return x*x} //一个计算乘积的内联函数
printf(COUNT(3)); // 结果为 COUNT(3) ( 3 * 3) = 9;
printf(count(3)); // 结果为 count(3){return 3*3 }=9;
上面的例子好象不足以说明两者的区别,我们把上面的例子的调用改改,再看看结果
printf(COUNT(2+3)); //结果为COUNT(2+3)(2+3 * 2+3) = 11
printf(count(2+3)); //结果为count(2+3){return 5*5 ;} = 25;
如果宏要达到乘积为25的结果,应该这样写:
#define COUNT(X)((X)*(X))
对应到上面的例子就是 #define COUNT(2+3)((2+3)*(2+3))
[ 随手记 1 ] C/C++宏,普通函数,内联函数的更多相关文章
- 【C语言】预处理、宏定义、内联函数 _
一.由源码到可执行程序的过程 1. 预处理: 源码经过预处理器的预处理变成预处理过的.i中间文件 1 gcc -E test.c -o test.i 2. 编译: 中间文件经过编译器编译形成.s的 ...
- 【C语言】预处理、宏定义、内联函数
一.由源码到可执行程序的过程 1. 预处理: 源码经过预处理器的预处理变成预处理过的.i中间文件 1 gcc -E test.c -o test.i 2. 编译: 中间文件经过编译器编译形成.s的汇编 ...
- C++(十七) — 宏代码、内联函数
1.C++ 表达式返回值 返回引用:当函数返回引用类型时,没有复制返回值.相反,返回的是对象本身.(与之对应的C语言中,返回的是变量的值) C++中,表达式返回的是变量本身(也就是变量对应的地址). ...
- 宏 函数 内联函数inline
带参宏有时候可以代替函数作用:优点直接替代,省去函数调用过程的开销:但缺点也是很明显:容易出错,系统不做检查非常容易出错. 改进方案:内联函数:既有带参宏的直接替代(拷贝)的优点,又有系统检查的优点. ...
- C++ 函数 内联函数
内联函数的功能和预处理宏的功能相似,在介绍内联函数之前,先介绍一下预处理宏.宏是简单字符替换,最常见的用法:定义了一个代表某个值的全局符号.定义可调用带参数的宏.作为一种约定,习惯上总是用大写字母来定 ...
- C语言中宏定义与C++中的内联函数
一,宏定义:在预处理的时候把宏定义的内容替换到代码中,正常编译. 1,无参数宏定义和有参数宏定义 (1)宏定义不能加分号,比如:#define PI 3.24;错的,#define PI 3.24 ...
- 带参宏定义和inline修饰的内联函数
带参宏定义和inline修饰的内联函数都是在编译时,用函数体替换掉宏调用或函数调用.这样用的好处是减少调用函数所花费的时间. 例如: 算法导论在讲到堆排序时说的,好的堆排序实现一般是把Left(i), ...
- C++内联函数
在C语言中,我们使用宏定义函数这种借助编译器的优化技术来减少程序的执行时间,那么在C++中有没有相同的技术或者更好的实现方法呢?答案是有的,那就是内联函数.内联函数作为编译器优化手段的一种技术,在降低 ...
- C/C++ 内联函数
内联函数具备一般函数的性质,但是不需要调用,而是在编译阶段,会用函数体替换函数名被调用的地方.可以节省调用时间(进出栈.保存上下文). 在编译层面和宏的作用相同.内联函数的展开在编译阶段,宏展开在预处 ...
随机推荐
- Oracle11g导出为Oracle10g版本数据,解决10g不兼容11g文件
EXPDP USERID='JCSJ/JCSJ@FZBD' schemas=JCSJ directory=bac_file dumpfile=JCSJ.dmp logfile=JCSJ.log ver ...
- LINQ之路14:LINQ Operators之排序和分组(Ordering and Grouping)
本篇继续LINQ Operators的介绍,这里要讨论的是LINQ中的排序和分组功能.LINQ的排序操作符有:OrderBy, OrderByDescending, ThenBy, 和ThenByDe ...
- Hadoop数据类型
hadoop包装了java的基本数据类型使他们实现以上的接口而且给予实现细节,这些类都实现了WritableComparable接口,能够在不同的hadoop节点之间毫无障碍的传输了.
- C# winform 选择文件保存路径
1.winform 点击按钮选择文件保存的路径,效果如下图: 具体代码如下: private void button8_Click(object sender, EventArgs e) { Fold ...
- minicom 安装 查看串口
因为现在电脑基本不配备串行接口,所以,usb转串口成为硬件调试时的必然选择.目前知道的,PL2303的驱动是有的,在dev下的名称是ttyUSB0 默认情况下ubuntu已经安装了USB转串口驱动(p ...
- Windows 用bat脚本带配置启动redis,并用vb脚本使其在后台运行。
最近,在Windows上用开发PHP程序,需要用到Redis,每天要打开一个运行redis-server.exe的窗口这样比较烦,因为窗口就一直打开着,不能关闭. 所以就想着通过写脚本的方式,让他在后 ...
- [译] 关于 Angular 依赖注入你需要知道的
如果你之前没有深入了解 Angular 依赖注入系统,那你现在可能认为 Angular 程序内的根注入器包含所有合并的服务提供商,每一个组件都有它自己的注入器,延迟加载模块有它自己的注入器. 但是,仅 ...
- postman(七):运行集合,看所有请求执行结果
当在一个collection中录好接口测试用例后,可以利用postman提供的“Run collections”功能来批量执行集合下的所有请求 点击顶部菜单中的[Runner] 或者也可以直接在想 ...
- 雷林鹏分享:jQuery EasyUI 数据网格 - 列运算
jQuery EasyUI 数据网格 - 列运算 在本教程中,您将学习如何在可编辑的数据网格(datagrid)中包含一个运算的列.一个运算列通常包含一些从一个或多个其他列运算的值. 首先,创建一个可 ...
- POJ-3294 Life Forms n个字符串中出现超过n/2次的最长子串(按字典序依次输出)
按照以前两个字符串找两者的最长公共子串的思路类似,可以把所有串拼接到一起,这里为了避免讨论LCP跨越多个串需需要特别处理的问题用不同的字符把所有串隔开(因为char只有128位,和可能不够用,更推荐设 ...