小言_互联网的博客

c中对宏的理解(面试题)

368人阅读  评论(0)

1、gcc的编译过程:预处理、编译、汇编、链接

预处理:宏替换、删除注释、头文件包含、条件编译 -E (不会发生报错)生成预编译文件
将 01_code.c文件使用 gcc -E 01_code.c -o 01.i生成预编译文件01.i

可以10行的源文件看见生成800多行的预编译文件

编译:将预编译之后的文件编译成汇编文件

汇编:将汇编文件生成二进制文件

链接:将工程中的各个二进制文件+库函数+启动文件 生成可执行文件

edu@edu:~/work/c/day_03$ gcc 01.o -o 01

或者可以直接由预编译文件一步到位

2、宏的了解

使用关键字define叫做宏

#define MA 3                          //宏的定义形式(宏定义)

在预处理的时候使用 3 代替所有MA出现的位置(宏展开)
注意:不要再宏后面加 分号

#define MA 3;                          //错误的宏定义形式
if (MA>2){
      //这个表达式中 就会出现 3; > 2这样的情况,所以加分号这种宏定义形式是错误的
   printf("大于\n");
}

3、不带参数的宏

宏的定义范围:是从定义处开始当前文件结束 都有效
#under可以结束宏的作用域(但是这个是不常用的)
宏没有归属,只有在当前文件中有效


#include <stdio.h>
void test06()
{
   
#define N 100 // 宏没有归属感,只要不影响使用,可以定义在当前文件中的任何位置中,所以这种定义方式也是正确的
    printf("N = %d\n", N);
}
int main(int argc, char const *argv[])
{
   
    test06();
    return 0;
}

4、带参数的宏

#include <stdio.h>
#define MY(a, b) a *b
void test00()
{
   
    printf("MY(a,b) = %d\n", MY(2, 3)); // 使用 10*20代替 MY(2, 3)
}
int main()
{
   
    test00();
}


使用 gcc -E 01_code.c -o 01.i进行预编译

注意事项:

(1)、宏定义的时候不能有数据类型

(2)、宏定义不能保证参数的完整性

#include <stdio.h>
#define MY(a, b) a *b
#define MY_1(a, b) a *b
#define MY_2(a, b) ((a) * (b))
#define MY_3(a, b) (a) * (b)
void test00()
{
   
    printf("MY(a,b) = %d\n", MY(2, 3));             // 使用 a*b代替 MY(2, 3)
    printf("MY_1(a,b) = %d\n", MY_1(2 + 2, 3 + 3)); // 2 + 2 * 3 + 3
    printf("MY_2(a,b) = %d\n", MY_2(2 + 2, 3 + 3)); //((2+2) * (3 + 3))
    printf("MY_3(a,b) = %d\n", MY_3(2 + 2, 3 + 3)); //(2+2) * (3 + 3)
}
int main()
{
   
    test00();
}

 


(3)、宏不能作为 类、结构体的成员

5、带参宏(宏函数)和带参函数的区别

(1)、带参宏调用多少次就会展开多少次,执行代码的时候没有函数的调用过程,不需要压栈和弹栈,所以带参宏是浪费了栈的空间,因为在预编译的时候被多次展开,所以节省时间(典型的使用空间换取时间)
(2)、带参数的函数,只有一段,存储在代码段,所以在编译阶段会进行多次压入栈中、退出栈中,所以节省了空间,但是压栈和退栈浪费了时间(典型的使用时间换取空间)
(3)、带参数的函数中的参数有数据类型定义,但是带参宏中没有数据类型的定义


转载:https://blog.csdn.net/qq_51691366/article/details/128766399
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场