C语言--宏定义和inline学习

编译器使用的是gcc。在学习C语言的宏定义和inline关键字修饰函数时,为了能很好的明白二者的区别,所以这里就记录下二者在预处理时生成中间文件的区别。

宏定义:
  • 优点:不会生成中间代码,在调用处会直接替换掉指定的宏名称
  • 缺点:不会检测传入的参数合法性和参数的类型,只是在调用的位置进行了简单的替换

生成中间文件的区别

1.宏定义
使用宏的方式很简单,通过关键字#define 标志名 表达式的格式来定义宏,如果是多个表达式的方式,则需要\的方式来增加多个表达式,如下函数

#include <stdlib.h>

#define add(x,y) ((x)+(y))
#define TAG "MACRO"
#define log(tag,msg) printf(#tag ":%s\n" ,#msg)

int main()
{
    int a=10;
    int b=9;
    int c=add(a,b);
    const char* msgxx="test macro";
    printf("c=%d\n",c);
    printf("TAG:%s\n",TAG);
    log("aaa",msgxx);
    return 0;
}

通过gcc -E main.c -o main.i 查看中间文件 ,省略掉引入头文件的内容,如下是预编译代码

//省略的头文件中间代码
# 3 "main.c" 2
# 8 "main.c"
int main()
{
    int a=10;
    int b=9;
    int c=((a)+(b));
    const char* msgxx="test macro";
    printf("c=%d\n",c);
    printf("TAG:%s\n","MACRO");
    printf("\"aaa\"" ":%s\n" ,"msgxx");
    return 0;
}

对比源码可以发现,调用宏add处的代码被替换成了宏的标签名后的表达式,TAG也被替换为了MACRO,tag和msg也被传入的替换掉,这样以后在看源码的时候,在看到宏定义的调用时就可以联想到这里实际是在最后会被替换层为宏后面的表达式。
如果这里将add函数的参数传递传入一个字符,那么这里是不会进行检测测试,而是直接计算结果返回

#include <stdio.h>
#include <stdlib.h>
#include "minline.h"
#define add(x,y) ((x)+(y))

int main()
{
    int a=10;
    int b=9;
    int c=add(a,'c');
    const char* msgxx="test macro";
    printf("c=%d\n",c);
    return 0;
}

输出结果为:c=109,明显这里并没有检测出传入的参数是int类型还是char类型的字符串,为了解决这个问题,引入的inline的方式。因为inline就是一个函数,可以对参数类型和返回结果做一个检验。

inline修饰的函数:继承了宏的优点,同时会进行参数的类型和返回结果检测,inline函数实际还是一个函数
  • inline修饰的函数,在声明处使用inline关键字修饰没有意义,只在定义才有意义,因此推荐inline函数可以在头文件中定义。
  • 分类:inline , extern inline , static inline 三种。
  • 使用gcc编译时,inline函数会在当前的源文件中展开,在外部引用时,inline函数生成独立的函数汇编代码,
  • static inline 编译器本地展开
  • extern inline 不会生成独立的汇编代码
  • 不能将inline函数做太复杂的操作,如果太复杂实际将会被解释为函数

测试使用声明的头文件

#ifndef MINLINE_H
#define MINLINE_H
#include <stdio.h>

void iinline()
{
    printf("calling iinline \n");
}


#endif // MINLINE_H

源码

#include <stdio.h>
#include <stdlib.h>
#include "minline.h" //引入自定义头文件,使用""的方式
//#define add(x,y) ((x)+(y))
//#define TAG "MACRO"
//#define log(tag,msg) printf(#tag ":%s\n" ,#msg)
void minline ();//声明 inline
static void sinline ();//声明static inline
extern inline void  iinline();
inline void minline(){
    printf("minline calling\n");
}
static inline  void sinline(){
    printf("static inline calling\n");
}

int main()
{
//    int a=10;
//    int b=9;
//    int c=add(a,b);
//    const char* msgxx="test macro";
//    printf("c=%d\n",c);
//    printf("TAG:%s\n",TAG);
//    log("aaa",msgxx);
    minline();
    sinline();
    iinline();
    return 0;
}

中间代码

# 3 "main.c" 2
# 1 "minline.h" 1
# 5 "minline.h"
void iinline()
{
    printf("calling iinline \n");
}
# 4 "main.c" 2
void minline ();
static void sinline ();
extern inline void iinline();
inline void minline(){
    printf("minline calling\n");
}
static inline void sinline(){
    printf("static inline calling\n");
}
 int main()
{  
    minline();  
    sinline();
    iinline();
    return 0;
}  

可以看出来,inline修饰的函数实际在预处理阶段还是被处理的函数,并不会像宏那样在对应位置展开。

猜你喜欢

转载自blog.csdn.net/LoopherBear/article/details/81839096