回 帖 发 新 帖 刷新版面

主题:[讨论]内联函数,一般函数,宏的透彻理解,所有人进


一本书上说:
调用内联函数时,编译系统直接将内联函数代码替换到主函数调用的地方,而普通函数则是通过参数传递。
    那内联函数不和宏替换一样了吗?
    那内联函数会不会遇到和宏一样的问题
例如以下是一个用内联函数实现的代码:
(我用的Dev)
#include<stdio.h>
#include<stdlib.h>
inline int sq(int);
int main()
{
     int i=1;
     while(i<=5)printf("%d ",sq(i++));
     printf("\n");
                
     system("PAUSE");
     return 0;
     }
inline int sq(int y)
{
    return (y)*(y);
}
运行结果为1 4 9 16 25




这个是用宏实现的
#include<stdio.h>
#include<stdlib.h>
#define sq(y) ((y)*(y))
int main()
{
     int i=1;
     while(i<=5)printf("%d ",sq(i++));
     printf("\n");
                
     system("PAUSE");
     return 0;
     }
运行结果为1 9 25   原因是宏替换时(i++)*(i++)每次i都自增了两次


有人说内联有点类似   那它们会遇到相同的问题吗?(在我举的例子中没有遇到,也许是没有内联编译系统把它当一般函数处理了,所以和大家讨论一下)

它们有区别吗?

回复列表 (共12个回复)

沙发

有区别。
宏,预编译处理
inline ,编译时处理
其他一切差异都由此而出。

板凳

谁说inline就一定会展开?
带有switch或是循环的一般不会展开。传递对象时使用值传递的一定不会展开。

3 楼

inline在C99里才有的吧,现在的很多编译器还不支持,我用KEIL测试在C51中没有此关键字。
[code]
     5: int main() 
     6: { 
     7:      unsigned char i=1; 
     8: //       P0 = sq(i++); 
     9: //       P1 = sq(i++); 
C:0x000F    7F01     MOV      R7,#0x01
    10:          P2 = sq1(i); 
    11:  
C:0x0011    12001A   LCALL    sq1(C:001A)
C:0x0014    8FA0     MOV      P2(0xA0),R7
    12:      return 0; 
C:0x0016    E4       CLR      A
C:0x0017    FE       MOV      R6,A
C:0x0018    FF       MOV      R7,A
    13:      } 
    14:  
C:0x0019    22       RET      
[/code]

4 楼

[code]
测试
[/code]

5 楼

[quote]inline在C99里才有的吧,现在的很多编译器还不支持,我用KEIL测试在C51中没有此关键字。
[code]
     5: int main() 
     6: { 
     7:      unsigned char i=1; 
     8: //       P0 = sq(i++); 
     9: //       P1 = sq(i++); 
C:0x000F    7F01     MOV      R7,#0x01
    10:          P2 = sq1(i); 
    11:  
C:0x0011    12001A   LCALL    sq1(C:001A)
C:0x0014    8FA0     MOV      P2(0xA0),R7
    12:      return 0; 
C:0x0016    E4       CLR      A
C:0x0017    FE       MOV      R6,A
C:0x0018    FF       MOV      R7,A
    13:      } 
    14:  
C:0x0019    22       RET      
[/code][/quote]

我擦,大哥, KEIL在C51,您就别指望inline了。干活儿的地儿不一样,怎么会一样的标准呢。

6 楼

另:内联函数不会有楼主描述的那个宏函数的的毛病~~~~

7 楼

[quote]谁说inline就一定会展开?
带有switch或是循环的一般不会展开。传递对象时使用值传递的一定不会展开。[/quote]

恩,确实有些情况先inline也会失败。
gcc的inline有3种:(不过我不清楚C99是怎么描述inline的)
1。 inline : 普通内联,如果内联失败,被当做普通函数对待,是全局的。
2。 static inline:和inline差不多,只是如果内联失败,被当做static函数对待。
3。 extern inline:不管内联失败与否,都不会生成函数代码.如果内联失败,一般程序
      也出现连接错误,找不到某某函数或某某函数未定义什么的。

如果把 优化关掉,inline, static inline 函数都不会内联。
一般的函数,包括简单的有循环的函数,gcc一般都能内联成功。
甚至有些简单的递归函数都能内联成功。

8 楼

[quote][quote]谁说inline就一定会展开?
带有switch或是循环的一般不会展开。传递对象时使用值传递的一定不会展开。[/quote]

恩,确实有些情况先inline也会失败。
gcc的inline有3种:(不过我不清楚C99是怎么描述inline的)
1。 inline : 普通内联,如果内联失败,被当做普通函数对待,是全局的。
2。 static inline:和inline差不多,只是如果内联失败,被当做static函数对待。
3。 extern inline:不管内联失败与否,都不会生成函数代码.如果内联失败,一般程序
      也出现连接错误,找不到某某函数或某某函数未定义什么的。

如果把 优化关掉,inline, static inline 函数都不会内联。
一般的函数,包括简单的有循环的函数,gcc一般都能内联成功。
甚至有些简单的递归函数都能内联成功。[/quote]
嘿嘿,这我还真不太了解。不过对于VC等编译器,inline就是static的,不管inline成功与否,都不会在全局符号表中留下任何东西:)

9 楼

[quote][quote]谁说inline就一定会展开?
带有switch或是循环的一般不会展开。传递对象时使用值传递的一定不会展开。[/quote]

恩,确实有些情况先inline也会失败。
gcc的inline有3种:(不过我不清楚C99是怎么描述inline的)
1。 inline : 普通内联,如果内联失败,被当做普通函数对待,是全局的。
2。 static inline:和inline差不多,只是如果内联失败,被当做static函数对待。
3。 extern inline:不管内联失败与否,都不会生成函数代码.如果内联失败,一般程序
      也出现连接错误,找不到某某函数或某某函数未定义什么的。

如果把 优化关掉,inline, static inline 函数都不会内联。
一般的函数,包括简单的有循环的函数,gcc一般都能内联成功。
甚至有些简单的递归函数都能内联成功。[/quote]


对于gcc,不管优化与否,都可以用函数属性强制内联:
__attribute__((always_inline))

10 楼

不要太追求inline,要坚信编译器往往会比你做的好。
有些函数inline后效率反而会降低:)

我来回复

您尚未登录,请登录后再回复。点此登录或注册