
[导读] C语言中宏是非常有价值的语言特性之一,也是面试中必考察的要点之一,本文来分享总结一些关于宏的常见面试问题。希望能帮助到有需要的小伙伴们。 宏工作原理以hello word程序为例来看看,将下述代码存成hello.c #include <stdio.h>#define STR "hello world" /*这是一个hello word程序*/ int main(void) { printf("%s",STR); return 0; } 为了说明问题,这里用下面的命令进行显式预处理,将得到hello.i文件,实际编译过程中,会自动完成。 //gcc -E 生成预处理文件gcc -E hello.c -o hello.i 来大致看看hello.i文件 # 1 "hello.c"# 1 "<built-in>" # 1 "<command-line>" # 1 "/usr/include/stdc-predef.h" 1 3 4 #删除很多行 ....... extern char *ctermid (char *__s) __attribute__ ((__nothrow__ , __leaf__)); # 912 "/usr/include/stdio.h" 3 4 extern void flockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)); extern int ftrylockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) ; extern void funlockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)); # 942 "/usr/include/stdio.h" 3 4 # 2 "hello.c" 2 # 4 "hello.c" int main(void) { printf("%s","hello world"); return 0; } 上面这步操作做了三件事情:
#include <stdio.h> #define PRINT_HELLO(i, times) do \ { \ if (i++ < times) \ { \ printf("嵌入式客栈\n"); \ continue; \ } \ }while(1) int main() { PRINT_HELLO(0, 3); return 0; } 答案:D 解析:PRINT_HELLO宏在预处理器时被扩展。宏展开后,if表达式变为:if(0 ++ <3)。0是一个常数,常数如何自增呢?,因此应用增量运算符会产生编译时错误。 面试问题2#include <stdio.h> #if A == 3 #define B 3 #else #define B 5 #endif int main() { printf("%d", B); return 0; } 答案:B 解析:乍一看,输出似乎是编译时错误,因为尚未定义宏A,所以A是不等于3的,所以会将B定义为5。你如不信,也可以用上面的办法gcc -E hello.c -o hello.i来验证,或者编译运行一遍。 面试问题3#include <stdio.h> #define X 3 #if !X printf("嵌入式"); #else printf("客栈"); #endif int main() { return 0; } 答案:C 编译错误 解析:程序编译三部曲:预处理、汇编、链接,那么在预处理时,上述代码就变成下面这样: #这里还有stdio.h的包含内容printf("客栈"); int main() { return 0; } printf在main外面被调用了,所以编译会出错。 面试问题4#include <stdio.h> #define IS_EQUAL(X, Y) X == Y int main() { #if IS_EQUAL(X, 0) printf("嵌入式"); #else printf("客栈"); #endif return 0; } 答案:A 解析:条件宏#if IS_EQUAL(X,0)扩展为#if X ==0。预处理结束后,所有未定义的宏均使用默认值0初始化。 面试问题5#include <stdio.h> #define SQUARE(x) x*x int main() { int x; x = 2000/SQUARE(10); printf("%d", x); return 0; } 答案:B 解析:预处理器用10*10替换SQUARE(10),表达式变为 x = 2000/10 * 10,x的值计算为2000。如前所说,应定义如下: #define SQUARE(x) ((x)*(x))面试问题6 # include <stdio.h> # define scanf "%s Embedded Inn " int main() { printf(scanf, scanf); return 0; } 答案:D 解析:在编译的预处理阶段之后,printf语句将变为。 printf(“%s Embedded Inn”,“%s Embedded Inn”);面试问题7 #include <stdio.h> #define STR "嵌入式" int main() { printf("%s",STR); #define STR "客栈" printf("%s",STR); return 0; } 答案:B 解析:如果重新定义预处理程序指令,则预处理器不会给出任何错误,它可能会发出警告。预处理器在使用之前获取新值,并将其替换。 ![]() #include<stdio.h> #define ADHESION(x,y) x##y int main() { int var1 = 100; printf("%d", ADHESION(var,1)); return 0; } 答案:A 解析:运算符##称为“令牌粘贴(Token-Pasting)”或“合并(Merge)”运算符。它将两个符合合并为一个。因此在预处理之后,printf变为。 printf("%d", var1);面试问题9 #include <stdio.h> #define MAX 6666.6f int main() { float MAX = 666.6; printf("%f ", MAX); return 0; } 答案:C 解析:展开一看便知。 int main(){ float 6666.6 = 666.6; //常数不可为左值 printf("%d ", 6666.6); return 0; } 面试问题10 #include <stdio.h> #define macro(n, a, i, m) m##a##i##n #define MAIN macro(n, a, i, m) int MAIN() { printf("嵌入式客栈"); return 0; } 答案:B 解析:不注意可能会选A,认为将MAIN敲成大写了,其实仔细一看,通过前面两个宏以及粘连操作符##将MAIN替换成main,所以没有问题,这个题目比较骚,主要考察细心以及粘连操作符。 总结一下
本文总结了宏的基本工作原理,以及10个比较典型的面试问题,相信对于宏理解不深的盆友会有些许帮助。 |