|
1、情景再现 咬金,C语言学得怎么样了? 我都敲了2年C代码了,还有我不知道的吗? 4 L" q6 g( q: Y$ b 你狂,你继续狂!那我问你#error,#warning,#def这三个预编译干啥的? 额~~~,这就尴尬了,平时看代码基本上都见过,没怎么研究过哦。 ( W0 M! o2 h* l9 H+ F- ?& F; J4 q4 R+ H& V 哈哈~,要不要我教教你呀? 小鲁班,跟大哥说说呗! 4 k% v) H/ g9 K& H# h4 x7 o. w+ }1 W4 s 行吧,待会说我这队友啥也不懂!# L& `, E1 D3 O8 D; W; | 1 #error 与#warning 谈到预编译大家常用的有#if、#else、#ifdef、#ifndef、#endif等等条件编译选项。$ D1 N6 V, \; f1 t/ H5 ~ 然而在我们阅读一些大型的代码或者库的时候,一般都会看到有#error和#warning,可能有些小伙伴一扫而过并没有了解清楚这些预编译指令到底该怎么用,写了很久的代码估计也重来没有敲过他们。 : m% W' t. k5 a; q O5 M9 ?
参考demo:#include <stdio.h> #include <stdlib.h>$ j/ C9 z0 ?! O: X* j9 h //#define configUART_N 5 4 W5 o2 \! C& s, C" | ^ #ifndef configUART_N #error configUART_N must define+ Z' z3 W0 b* `+ M5 n7 e) [& D // #error "configUART must define"/ p' m" ?" |( h // #warning "configUART must define" #endif+ u+ ^5 s# o" ~/ ?* b }; M7 `! I% E" w) I+ ]6 \6 U" J, P7 m #if configUART_N > 41 j- ^* M$ r9 N Y #error configUART_N must not be less than 4 // #error "configUART_N must not be less than 4"4 \- J1 ?5 S0 ^) v, L // #warning "configUART_N must not be less than 4"' o/ K |; `( G* D2 I) D #endif /***************************************+ n. i$ R: t0 H* h: \5 h * Fuction: 进行预编译测试 0 h1 P3 D) ^$ Y/ A * Author 最后一个bug) **************************************/2 s3 K- h& j8 w: z' @% E int main(int argc, char *argv[]) { printf("公众号;最后一个bug\n");7 }( ~4 @3 \& D/ y" c( O6 s return 0; } 输出结果: ! m+ m* R/ V$ L/ L- C3 |
解释一下:
# a4 n7 X/ B' ]
( U& [+ |/ Q( k4 I8 C# } 2 #undef #undef标识符用于把前面的宏定义名取消,别看这宏用得不多,作用可大着呢,下面我简单举几个例子: % Y# f1 i6 I8 `: S) J 1 局部宏定义 一旦定义了宏,那么该文件中往下所有的代码都可以使用该宏,即使是函数内部,这样导致宏比较混乱,如下面代码:& R! y1 R n" q- E% w 参考demo:#include <stdio.h> #include <stdlib.h>0 L. W) ^: }; A: ] $ }6 R" O7 `, S7 F8 o0 ]* C% {7 t #define configRatio 10 /*************************************** * Fuction: 获得传感器电压值 * Author 最后一个bug) **************************************/ int GetSensorVolt(void) { ' Z6 S! d0 J* J3 h. x/ h4 @# X/ N #define configRatio 1 int ret = 0; ret = configRatio*1024; //比例因子*AD值 ( o* Q+ y* [0 i: ~- q& P m' u return ret; //#undef configRatio }# @) f! h! [ T8 n5 }* A' f: \' J /***************************************! |6 I( {) C) d( D6 C * Fuction: 获得传感器电压值 3 s' P+ ^; D4 g! Z" M * Author 最后一个bug) ; @8 B g* K* D3 y**************************************/ int GetSensorCurr(void) { : G: T9 D2 H7 W! P #define configRatio 2 Y2 j' h. T2 g( a! Q6 t5 x int ret = 0;' {% |1 l( v" z ret = configRatio*1024; //比例因子*AD值 return ret;; _' Z8 E5 X) s: b" m7 x //#undef configRatio } ! L& p; X; H3 b/ }+ X /***************************************9 [4 b3 j8 M3 {, l' s4 a * Fuction: 进行预编译测试 * Author 最后一个bug) **************************************/. V+ w V% B/ \2 x int main(int argc, char *argv[]) {3 b. |1 I* _. c . A: G' T$ g) ~ printf("configRatio = %d\n",configRatio); //报宏未定义 . K/ F' ^5 L! p3 V+ G printf("GetSensorVolt = %d\n",GetSensorVolt()); 4 P2 L# r) D" Y; U9 h3 {: b( Z6 b3 f printf("GetSensorCurr = %d\n",GetSensorCurr()); printf("公众号;最后一个bug\n");2 W, n: ?; {* t: _: X/ d return 0; } 输出结果:
解释一下:
, J1 r* W3 X0 |5 K$ ~
0 t7 K6 k. [- b$ r4 [* \) [ 2 选择接口 ' l- o& i6 I4 P" G0 d! c 通过宏来切换不同的接口供程序使用: 参考demo:#include <stdio.h> #include <stdlib.h>. M6 w* F- N# B8 |8 r: ]) W #include <string.h>+ B, z3 }* k/ m u& X1 a( Q8 T. _1 s 9 Q# e- w) t: b; G! x- w8 x e6 W+ D/ B m& P" g #define DEV_SPI2 m' k: a6 ]3 o/ w2 [. M #include "Drive.h" #undef DEV_SPI- w; G4 t& d0 @; p0 G- P /*************************************** * Fuction: 进行预编译测试 * Author 最后一个bug) **************************************/ int main(int argc, char *argv[]) {8 P/ m7 N8 k9 p4 L 1 m4 c6 V; j+ v% r8 D9 |, m4 W# z char *strbug = "the last bug" ; SendData(strbug);: u1 e4 x' m2 W- |3 w% J ProcessData(strbug);7 v2 p, G+ k/ H$ T8 Q1 [; U" ` Q printf("公众号;最后一个bug\n"); return 0;+ S& ~7 F* H: {. N% [, O } & c) Y, _; L% A9 N1 `! s$ v' w #include <stdio.h>4 W+ w' V0 N- q) E% e/ g% C #ifdef DEV_UART . W4 W: ]/ N0 \& w: G #define SendData(s) printf("UART Send:%s\n",s) #define ProcessData(s) printf("UART Process:%s\n",s)+ Y( f" Q3 L: H) L6 l #endif3 e: V* G- B8 r( S1 g+ n( b 5 |$ f$ A$ U9 C! Y4 O #ifdef DEV_CAN3 g1 b" @5 H& I6 @! k #define SendData(s) printf("CAN Send:%s\n",s)# [6 W; m6 E: w$ U3 o8 {& m" e #define ProcessData(s) printf("CAN Process:%s\n",s)+ ?0 d' o5 e7 L % n% [! z- |0 J6 v" Q #endif & w2 |, d' Y( T9 Q% c/ k1 Z #ifdef DEV_SPI, x9 R# i8 e9 i8 I) v( E; d #define SendData(s) printf("Spi Send:%s\n",s)/ f9 w4 f# v0 J0 ]4 x/ E3 O8 V& ~ #define ProcessData(s) printf("Spi Process:%s\n",s) #endif( Q/ S, o1 \1 K6 p! ? 输出结果: # D* u) ]; X# u. R" X _/ h: s3 Y
3 自定义接口 当多个人维护一套代码的时候,有些同事喜欢调用库函数接口,而有些同事喜欢调用自定义接口,为了方便统一使用自定义接口或者库接口,我们会进行如下操作: 参考demo:#include <stdio.h> #include <stdlib.h>6 f' q6 s4 j2 ~1 T. v4 k #include <string.h> #include "Drive.h"9 r7 H+ P( V1 D- V) X9 f9 V7 J; h; G //#undef printf% D2 d. N4 g0 K6 x, N( P% c% i 3 E9 E8 K- S0 i) _ /*************************************** * Fuction: 进行预编译测试 ( ? I) `& p$ ` * Author 最后一个bug) **************************************/ int main(int argc, char *argv[]) { ) O: e$ Q% K' M* Z3 n. p" I char *strbug = "the last bug" ; printf("公众号;最后一个bug\n");' o# L4 h8 j5 S return 0;0 ?8 d4 O# ?4 y }+ ^- I6 k3 X# @, c2 d# o0 a0 h) s #define __DRIVE_H__ #define printf printf("please use Kprintf!\n");& }6 [4 ~, T3 }% Q ( i8 j* m+ y o extern void Kprintf(char *str);# d! G) I8 R* B, X #endif 输出结果:
咬金,懂了没 ? 小鲁班,这些知识都被你学到了!666 2、结束语 上面这几个比较"冷门"的知识认真想想其实还是挺有用的,可能现在的产品都急于快速上市,对于代码的雕琢还有所欠缺的,一份成熟的代码不仅仅只是稳定,还有后期的维护、扩展等等都是值得考虑的。 |
微信公众号
手机版