
[导读] C语言中宏是非常有价值的语言特性之一,也是面试中必考察的要点之一,本文来分享总结一些关于宏的常见面试问题。希望能帮助到有需要的小伙伴们。 宏工作原理以hello word程序为例来看看,将下述代码存成hello.c #include <stdio.h>#define STR "hello world" /*这是一个hello word程序*/ int main(void)9 B# c' L! d$ b5 ~, Y: v% _. Z {6 V) O2 S- ? O o+ d" } printf("%s",STR); return 0; }$ K8 E3 P) _& h: o 为了说明问题,这里用下面的命令进行显式预处理,将得到hello.i文件,实际编译过程中,会自动完成。 //gcc -E 生成预处理文件gcc -E hello.c -o hello.i 来大致看看hello.i文件 # 1 "hello.c" h) u; ]+ Y- a f& L" f4 U# 1 "<built-in>"9 I0 @: r; H. s* F# X # 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__));% {3 I# X7 B) t4 w8 ?& y- g5 S# ~; @ extern int ftrylockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) ; extern void funlockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__));. q6 h* P$ s) m) `. r # 942 "/usr/include/stdio.h" 3 4' ^7 k9 r# E( M! |7 Y, y # 2 "hello.c" 2 # 4 "hello.c" int main(void)1 k% W q3 X9 j! V- W _ { C# |5 l# @/ V printf("%s","hello world");/ [8 c, {! T6 ?2 I return 0; } 上面这步操作做了三件事情:
#include <stdio.h> 8 P5 F4 `2 X) U #define PRINT_HELLO(i, times) do \ { \ if (i++ < times) \ { \ printf("嵌入式客栈\n"); \ T9 B8 I% B7 p( o5 x continue; \ ) w/ `6 }% w3 W# E" m- ~' H } \ }while(1) 9 \. i* o6 w6 {& s4 |) Z . \4 l( k6 N! P# W int main() 8 j" B: l9 X7 d5 [# y# S { PRINT_HELLO(0, 3); return 0; ; c1 k( M- ^9 s4 L8 L } 答案:D 解析:PRINT_HELLO宏在预处理器时被扩展。宏展开后,if表达式变为:if(0 ++ <3)。0是一个常数,常数如何自增呢?,因此应用增量运算符会产生编译时错误。 面试问题2#include <stdio.h> 5 i0 n0 n4 _& N! M2 S #if A == 3 . @% t, e1 I) Z #define B 3 #else #define B 5 + z3 K3 `: f" S& L* @' J5 \2 U #endif 3 ^% Y& e( u7 M* j, n7 K 4 E" a S7 f% m. m. A4 j int main() ; c' B$ S5 h* W: b5 N { % d9 B# r7 r) T: ~- | O4 _ printf("%d", B); - M3 e+ y- \$ |" O return 0; } 答案:B 解析:乍一看,输出似乎是编译时错误,因为尚未定义宏A,所以A是不等于3的,所以会将B定义为5。你如不信,也可以用上面的办法gcc -E hello.c -o hello.i来验证,或者编译运行一遍。 面试问题3#include <stdio.h> #define X 3 #if !X ' M }' L2 O- i& ?7 s6 @5 C printf("嵌入式"); #else printf("客栈"); #endif int main() 9 C; t! H2 _& Q9 ` ] { return 0; ( {: L9 O- \% }1 Q0 s2 `$ E }7 t2 @* K1 J: i) z( A' [ 答案:C 编译错误 解析:程序编译三部曲:预处理、汇编、链接,那么在预处理时,上述代码就变成下面这样: #这里还有stdio.h的包含内容printf("客栈"); int main()0 ]7 K. R3 p' m v9 @ {' T) F$ u& U+ \( R, m* N return 0; }# U& f0 H7 \3 y 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> ( o& a' N% `8 I( p #define SQUARE(x) x*x int main() C8 g4 ~5 t. s+ q L8 Q- t. v { & o9 V- A* @$ O int x; x = 2000/SQUARE(10); printf("%d", x); 3 O5 G( }" c, X0 Y* s! }8 G4 h. s0 K5 z return 0; } " F b! ?8 g; b/ e$ a5 N 答案:B 解析:预处理器用10*10替换SQUARE(10),表达式变为 x = 2000/10 * 10,x的值计算为2000。如前所说,应定义如下: #define SQUARE(x) ((x)*(x))面试问题6 # include <stdio.h> . q: G* J3 K, y' G5 V # define scanf "%s Embedded Inn " : F2 J/ w2 L3 g6 ^0 B! S int main() { printf(scanf, scanf); 3 m3 F: F; a( u& H3 c& G return 0; 7 j5 E% b( W9 O$ e; q } - x6 |% }: F" `8 `& ]* J7 O1 R 答案:D 解析:在编译的预处理阶段之后,printf语句将变为。 printf(“%s Embedded Inn”,“%s Embedded Inn”);面试问题7 #include <stdio.h> 4 G E+ u$ V# O9 @9 J #define STR "嵌入式" ' i7 g4 H0 f$ O( [( x# H int main() 8 c8 P/ Q2 s' c { 5 u2 Z0 z6 v, B) R printf("%s",STR); #define STR "客栈" " T a8 g; @. t" D) G+ Q/ | printf("%s",STR);0 n5 j* v2 E4 B/ d return 0; } 答案:B 解析:如果重新定义预处理程序指令,则预处理器不会给出任何错误,它可能会发出警告。预处理器在使用之前获取新值,并将其替换。 ![]() #include<stdio.h> #define ADHESION(x,y) x##y int main() { ; _+ c( O3 o, j int var1 = 100; ' ^" b& F3 y' W' q printf("%d", ADHESION(var,1)); / I/ z g7 A, n0 j7 e$ f! f; V$ _ return 0; } 答案:A 解析:运算符##称为“令牌粘贴(Token-Pasting)”或“合并(Merge)”运算符。它将两个符合合并为一个。因此在预处理之后,printf变为。 printf("%d", var1);面试问题9 #include <stdio.h> " Y5 ^% _# f! D3 ?+ i #define MAX 6666.6f int main() " J9 Q' I$ V1 K( X' h { float MAX = 666.6; 9 ^6 }/ m. V( ]- x' S printf("%f ", MAX); 9 F1 ~* u4 C" b$ ]( ?" Q return 0; } 8 Z# {" i0 G' V/ s8 e 答案:C 解析:展开一看便知。 int main()! k" b- o% |2 O2 s{/ M" |6 Z( }6 u5 E' u float 6666.6 = 666.6; //常数不可为左值: s6 v9 _$ O+ p; U# r5 G4 f, J' u printf("%d ", 6666.6); return 0; } $ X( S" _) X+ e$ |& B. | 面试问题10 #include <stdio.h> #define macro(n, a, i, m) m##a##i##n #define MAIN macro(n, a, i, m) ; t( V" f1 t/ X+ v. U0 F+ c 3 [0 ~0 ^, ~) |9 E8 x5 u int MAIN() { ! P: K- t0 B% n8 ^1 k printf("嵌入式客栈"); return 0; , y* q- h. S- @5 H' X/ a } 答案:B 解析:不注意可能会选A,认为将MAIN敲成大写了,其实仔细一看,通过前面两个宏以及粘连操作符##将MAIN替换成main,所以没有问题,这个题目比较骚,主要考察细心以及粘连操作符。 总结一下
本文总结了宏的基本工作原理,以及10个比较典型的面试问题,相信对于宏理解不深的盆友会有些许帮助。 |