C++的内联函数是不是可以用宏替代? 如果是,为什么还需要内联函数。

wtjd 2009-08-26 04:02:12
C++的内联函数是不是可以用宏替代? 如果是,为什么还需要内联函数。
...全文
449 27 打赏 收藏 转发到动态 举报
写回复
用AI写文章
27 条回复
切换为时间正序
请发表友善的回复…
发表回复
wtjd 2009-08-28
  • 打赏
  • 举报
回复
原理基本已经懂了,结帖给分。
licry01 2009-08-27
  • 打赏
  • 举报
回复
学习
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 mstlq 的回复:]
下面是其中一个区别,但区别绝不仅仅是下面的……
C/C++ code#define mf(x) (x)*(x)
inlineint f(int x){return x*x};int main
{int i=5;int j=mf(i++);//此时i==7;
i=5;
j=f(i++);//此时i等于6}
[/Quote]
.
zaiguo 2009-08-27
  • 打赏
  • 举报
回复
C++ Prefer const and inline to #define
yshuise 2009-08-27
  • 打赏
  • 举报
回复
大师也不一定对。
na2650945 2009-08-26
  • 打赏
  • 举报
回复
可以。
但是宏不艺术。
所以尽量少的用宏。
这就是大师说的。
shiweifu 2009-08-26
  • 打赏
  • 举报
回复
内联就是为了替代宏的。。
如果用C++就应该用内联替代宏
内联函数是编译时的,有类型检查
而宏只是单纯的字符串替换。。
写上inline只是给编译器建议展开函数

展开不展开还是由编译器决定的
pengzhixi 2009-08-26
  • 打赏
  • 举报
回复
来学习!!
wensheng_zh2007 2009-08-26
  • 打赏
  • 举报
回复
内联函数可以对参数类型进行检查。
PolarStorm 2009-08-26
  • 打赏
  • 举报
回复
如果要编写一个大型工程,请最好不要用宏来实现功能,因为这样在调试的时候很难发现错误。
原因是宏定义在编译之前完成。就算程序编译成功了,运行中的错误也很难被发现,编译的时候会发现断点都没有办法打。

同样的,常量最好也不要写在宏里
可以在.hpp文件中声明static const [type] [name];
在.cpp文件中定义const [type] [name] = [value];

例如:在test.hpp中声明static const std::string szTest;
在test.cpp中定义const std::string szTest = "test";
这样做的效果和宏定义一样,函数亦是如此。
weixiaoshashou 2009-08-26
  • 打赏
  • 举报
回复
最好用内联
ridge.chang 2009-08-26
  • 打赏
  • 举报
回复
支持一下10楼!!!
limit_clear 2009-08-26
  • 打赏
  • 举报
回复
玩C++尽量用内联,不要用宏
Wind_Runner 2009-08-26
  • 打赏
  • 举报
回复
学习了~~~
xiao_ke 2009-08-26
  • 打赏
  • 举报
回复
内联函数和宏两者都不可以说可以替代对方, 内联函数可以有返回值,可以递归,但是宏却不行!
宏可以使用# ## 而内联函数却没办法!

liuchangyu23 2009-08-26
  • 打赏
  • 举报
回复
#define ASPECT_RATIO 1.653

编译器会永远也看不到ASPECT_RATIO这个符号名,因为在源码进入编译器之前,它会被预处理程序去掉,于是ASPECT_RATIO不会加入到符号列表中。如果涉及到这个常量的代码在编译时报错,就会很令人费解,因为报错信息指的是1.653,而不是ASPECT_RATIO。如果ASPECT_RATIO不是在你自己写的头文件中定义的,你就会奇怪1.653是从哪里来的,甚至会花时间跟踪下去。这个问题也会出现在符号调试器中,因为同样地,你所写的符号名不会出现在符号列表中。
解决这个问题的方案很简单:不用预处理宏,定义一个常量:

const double ASPECT_RATIO = 1.653;

这种方法很有效。但有两个特殊情况要注意。
首先,定义指针常量时会有点不同。因为常量定义一般是放在头文件中(许多源文件会包含它),除了指针所指的类型要定义成const外,重要的是指针也经常要定义成const。例如,要在头文件中定义一个基于char*的字符串常量,你要写两次const:

const char * const authorName = "Scott Meyers";

另外,定义某个类(class)的常量一般也很方便,只有一点点不同。要把常量限制在类中,首先要使它成为类的成员;为了保证常量最多只有一份拷贝,还要把它定义为静态成员:


class GamePlayer {
private:
static const int NUM_TURNS = 5; // constant eclaration
int scores[NUM_TURNS]; // use of constant
...
};

还有一点,正如你看到的,上面的语句是NUM_TURNS的声明,而不是定义,所以你还必须在类的实现代码文件中定义类的静态成员:

const int GamePlayer::NUM_TURNS; // mandatory definition;
// goes in class impl.file

你不必过于担心这种小事。如果你忘了定义,链接器会提醒你。

旧一点的编译器会不接受这种语法,因为它认为类的静态成员在声明时定义初始值是非法的;而且,类内只允许初始化整数类型(如:int, bool, char 等),还只能是常量。
在上面的语法不能使用的情况下,可以在定义时赋初值:


class EngineeringConstants { // this goes in the class
private: // header file
static const double FUDGE_FACTOR;
...
};
// this goes in the class implementation file
const double EngineeringConstants::FUDGE_FACTOR = 1.35;

大多数情况下你只要做这么多。唯一例外的是当你的类在编译时需要用到这个类的常量的情况,例如上面GamePlayer::scores数组的声明(编译过程中编译器一定要知道数组的大小)。所以,为了弥补那些(不正确地)禁止类内进行整型类常量初始化的编译器的不足,可以采用称之为“借用enum”的方法来解决。这种技术很好地利用了当需要int类型时可以使用枚举类型的原则,所以GamePlayer也可以象这样来定义:


class GamePlayer {
private:
enum { NUM_TURNS = 5 } // "the enum hack" — makes
// NUM_TURNS a symbolic name
// for 5
int scores[NUM_TURNS];// fine
};

除非你正在用老的编译器(即写于1995年之前),你不必借用enum。当然,知道有这种方法还是值得的,因为这种可以追溯到很久以前的时代的代码可是不常见的哟。

回到预处理的话题上来。另一个普遍的#define指令的用法是用它来实现那些看起来象函数而又不会导致函数调用的宏。典型的例子是计算两个对象的最大值:


#define max(a,b) ((a) > (b) ? (a) : (b))

这个语句有很多缺陷,光想想都让人头疼,甚至比在高峰时间到高速公路去开车还让人痛苦。
无论什么时候你写了象这样的宏,你必须记住在写宏体时对每个参数都要加上括号;否则,别人调用你的宏时如果用了表达式就会造成很大的麻烦。但是即使你象这样做了,还会有象下面这样奇怪的事发生:

int a = 5, b = 0;
max(++a, b);// a 的值增加了2次
max(++a, b+10); // a 的值只增加了1次

这种情况下,max内部发生些什么取决于它比较的是什么值!
幸运的是你不必再忍受这样愚笨的语句了。你可以用普通函数实现宏的效率,再加上可预计的行为和类型安全,这就是内联函数:


inline int max(int a, int b) { return a > b ? a : b; }
不过这和上面的宏不大一样,因为这个版本的max只能处理int类型。但模板可以很轻巧地解决这个问题:


template<class T>
inline const T& max(const T& a, const T& b)
{ return a > b ? a : b; }

这个模板产生了一整套函数,每个函数拿两个可以转换成同种类型的对象进行比较然后返回较大的(常量)对象的引用。因为不知道T的类型,返回时传递引用可以提高效率。

顺便说一句,在你打算用模板写象max这样有用的通用函数时,先检查一下标准库,看看他们是不是已经存在。比如说上面说的max,你会惊喜地发现你可以后人乘凉:max是C++标准库的一部分。
有了const和inline,你对预处理的需要减少了,但也不能完全没有它。抛弃#include的日子还很远,#ifdef/#ifndef在控制编译的过程中还扮演重要角色。预处理还不能退休,但你一定要计划给它经常放长假。



摘自 Effective c++

建议阅读
yshuise 2009-08-26
  • 打赏
  • 举报
回复
宏可以生成c++代码,此刻编译,此刻执行。而函数(不用宏)生成的代码无法做到这一点,要重新编译才能执行。

晨星 2009-08-26
  • 打赏
  • 举报
回复
楼上们说的不错。
其实还有一点:
宏里的代码是必然要被现场展开,而且这一步是在预编译时就完成了。
而内联函数却不一定,是否真的内联展开,是编译器说得算的。编译器如果发现一个内联函数生成出来的目标代码很长很长,很可能就直接否决了程序员写的“inline”,在最终的目标代码中仍然使用一般的函数调用机制来调用它。这些是在编译或连接时完成的。所以,“inline”只是“建议内联”的意思。
starcat 2009-08-26
  • 打赏
  • 举报
回复
The reason for inline function is efficiency.Every time a fucntion is called, a series of instructions must be executed, both to set up the function call, including pushing any arguments onto the stack, and to return from the function. In some cases, many CPU cycles are used to perform these procedures. However, when a fucntion is expanded inline, no such overhead exists, and the overall speed of your program will increase.
visir 2009-08-26
  • 打赏
  • 举报
回复
内联函数可调试, 内联函数的有类型(参数和返回值)
加载更多回复(7)

64,644

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧