资源描述
宏打印函数在我们的嵌入式开发中,使用printf打印一些信息是一种常用的调试手段。但是,在打印的信息量比较多的时候,就比较难知道哪些信息在哪个函数里进行 打印。特别是对于异常情况的打印,我们需要快速定位到异常情况的位置。这时候我们可以使用宏定义来封装一个宏打印函数,这个宏打印函数可以显示打印信息所在的文件、行数、函数名等信息。如:#defi ne DBG _P RINTFfmt, args.) (prin tf(vvFile:%s Li ne:%d Fu nctio n:%s , _FILE N_);LINEFUNCTIOprin tf(fmt, #args);使用范例:ibPefl昌 *曲.翊EP:./STk/nJitlk. I;Funcllun ;TvsLt d * b - 3 HffllD wrliJi所任荷弓 灯tZQKjJ(3CT1H-EI RitHh i墨林(SI a时灵KtiIMC-IM -li. -.? 1. mJ fh: 119 SiteTHiD CytE215 static voia217218restotvQi 21t = 220I DBG PRINTKa f b = T.dn”,a ft);22122?static void bestl (void)223:2DEG PRINTF 110 VOrli) J224225 L可见,使用方法与printf的使用方法一样,而且每条打印语句开头都会打 印调试信息所 在的文件名、行号、函数名信息,方便我们查找一些调试信息。其中,一FILE、一LINE、FUNCTIONj这三个宏是编译器内置宏定义,分别代表调试信息所在文件、行号、函数。号TIME 一分别代表当前的编译日期除此之外,常用的宏还有:DATE、与时间。如:DBG_ PRINTF(Com pile Time: %s %sn”, _DATE_, _TIME_);.辰申口匿疣军.丈件;B 占 lifEl ijeicvi zacD 舌趣)几庐网H nvttUiSLl冉 n HIBnrrJ备申rTMm*帕5.ijLln :rile:$ IS .TTFunction ;.rw in Fund lunF j if : ,/Src/ruin Linp;117 i-f 1 Ip :“1 In D W1 fttiiD常vidK-dI 0叶仃In曾1: L -iin十卜irmt i!f . 1 FFRg: J5fl Byt.t第二条printf 中的符号是为了处理args不代表任何参数的情况。如:DBG_ PRINTF(Hello world);当不加符号是,以上宏的第二条语句被拓展为:prin tf(Helloworldn,);可见,多出了一个逗号,这个逗号是多余的。加上符号后,以上宏的第二条语句被拓展为:prin tf(Helloworldn);这才是我们想要的结果。其实这些结果我们通过查看预处理文件可以清晰的知道: 通莒 建贝 c r 11WI n deVrt&ystefn3 2cnnd.e;e口 回D: sttyCodeS 111321431 RC_)enCoAeS-E luiin.c - nain,iD: f1yCoi31elM32M31HCJ)moCodercEBaErnimsiBinEKsmaHiEaamMHErasH 士的定呗处迎讨柠厂细,为,EC vn3i-LilEHiS1岭1 皿1赎 I 17fl 1*71I棒坤 的IUR.I Rjrn_iULdk ujUT-HandATY 二 g+ nusr-tatotJLIcntj V 匚 iurri-iLi 飞上: Sa LLi-e:XJ FuricLIurzSi Fuj . c. 232. _: LfUZTL3i_.;d i- t - :Id .巧;不加#符号时,这里多出一?逗号IT: -f CX-ilcjis Lir.2 iSid 卜;/i 匚 ti二,nai- .c, j T15, _-ITK. I i*tl_ - printf 肿1 环T-C - 一:心.-.1r庶盲广-.ivoloi HU-U-述匕肌k umtha何曲Dfrf吓也:心幻讣 P ?; 7 Tiain.r:扶气1汐心.1 u * nt -I r n T 皿1 F 一 irji J HL r* inT 4L丽Ti|.-inilf ,Line Funcii 工_, Z35, _FUncnOH_ ; J li . d t b - :EciT . d t b加#符号后得到的正是我们想要的结果侦i1073lC7d;p-lntfLineFrHiw;怂小上rrsdn-ca 虻目七 _FUHCnCfl_ J预处理过程得到的文件最后需要注意的是,这个DBG PRINT还是与printf宏是两条语句 不一样的。DBGPRINTF的组 合,无返回值;而printf 的原型是一int printf (const char *_format,但是我们一般都很少使用printf的返回值,所以DBG _P RINTF勺用法与printf 函数基本一致。 打印调试宏开关在程序发布阶通常情况下,一些打印调试信息只是在我们调试阶段需要的,段是不需要的。所以,为了避免打印调试信息带来的资源开销,我们可以把这些打印调试语句给注释掉。一种方法是逐句进行注释,这是一种比较低效的方法。比较高效的方法就是添加调试宏开关,利用条件编译来选择打印/不打印调试信息。比如我们可以把上面的代码改造为:#defi ne DEBUG 1#if DEBUG#defi ne DBG _P RINTF(fmt, args.) (LINEFUNCTIprin tf(vvFile:%s Lin e:%d Fu nctio n:%s , _FILE.ON_);prin tf(fmt, #args); #else#defi ne DBG _P RINTF(fmt, args.) #en dif根据DEBU (宏的值来选择对应的打印宏函数。当DEBU 的值为1时启动相关的打印调试语 句,DEBU(的值为0时则关闭打印调试语句。这样我们就可以很方便的通过设置DEBUG宏的值来启动与关闭我们整个工程的DBG PRINT打印调试信息。dowhile(0)其实,上面我们封装的打印宏DBGPRINT还有一点缺陷,比如我们与if、else使用的时候, 会有这样的一种使用情况:230static void Test2void)2313(232int a = 1, b = 2;233int c = a + b; if (c)234DBG二PRINTFCc 0n);出现语寸去错误235DBG PRISfTFCc = OWVX 236237238 此时会报语法错误。为什么呢?同样的,我们可以先来看一下我们的dem。代码预处理过后,相应的宏代码C nair.i xvr会被转换为什么。如:F士叫讥卡 “”口:金口蕨 LirwiM rurctlsng, 占 2J2, _: p-l it+ a - b -汕-“3_LC丁rtfLirNrctlon:cS *F 占 217 _rLmCllO_ ;17诈DsaTlc 岬 Id -eBT2iptsL射普Int a - t =;:1的2i-:*上 D;临3piJntfPuncrlc: I * nhaLn.c, 135, _FWCTr: XJ_;尸:皿;z ex*、; eZsf1974C-Inli# : F9 I 电:! UM KunLdb-m rtgLft C.237. _fUKTICfJ_ ;片n-s : qeelseDEG PRINTFLc 0门*打elseDEG PRIHTFC v= 0EV*)以上两种方法都可以正常编译、运行了。但是,我们C语言中,每条语句往往以分号结尾;并且,总有些人习惯在if判断之后只有一条语句的情况下不加大括号;而且我们创建的dbg_print宏函数的目的就是为了对标printf 函数,printf 函数的使用加分号在任何地方的使用都是没有问题 的。基于这几个原因,我们有必要再对我们的dbg_print宏函数进行一个改造。下面引入dowhile(0)来对我们的DBG_PRINT进行一个简单的改造。改造后的DBG P RINT宏函数如下:#defi ne DBG _P RINTF(fmt, args.) do(prin tf(vvFile:%s Lin e:%d Fu nctio n:%s ,FILELINEFUNCTION-1prin tf(fmt, #args);while(0)这里的do.while循环的循环体只执行一次,与不加循环是效果一样。并且,可以避免了上面的问题。预处理文件:static void Test! Hold:CO Wtf职卜d 攻lew:鼬,,广&盯_卜圈匚;p陨祇卢ht&ll worEs* ; AhHestatic voidInt a - Ij b - 2 Ifll C J F 扫;doprin 计广巧 W; S Lig; 3d mnti 亦:霄rwin-L.;prirtf r 之 flvf ;册;:r&|eLzeprintf : / l.fZ* hi .I nA 孤 2】勺丽冷*:/ 4*tM If IIP- ._rAL_nrj. T二、a.d=、s H = .3.d=h Nk; D L rc= . 3:3 |= ._llM_&i._. YEJ Idi、土 aii_is.*_J 匚_直 I ITEF Ei| : -Hj I0 t 忙 Ml =! mLlei-BiI 皓 J4UIA *1J.U 1 |Ch J WIT-I* 11 I L亡I 1涵 I吊庇|匚 | a.iivKh J- mid :? JH| 即 Hl flF |l7p Uu|4l| J wnxl-v |C.| I aLc |l: t unim |l.| 1 &7-: r-7n u】*p-hl -寸二 fa J 皿 1:口 二亡 -Wit 地畤,”K_Afi5: MLrutjgra 13.宾:H Uf Z = Lt-a*-= el; 21 4nlLJl- =耳二* 岂 口【.匚_E-ir (KZC-MJifl IXD-K” 嘲 H_QBMI3t-6CEai 二 TPnTTTril ;H: .i 二二(:I j.IC zzirJr z .13 r :“T_色巧山匚顶 1 fhS , 工 IF Hii_lArfA . ifi.=二匕二 i.ii nZZ7: ?ra L rlT 二 t ?* 匹 ZT3 -十 AKE=CZ_ZEHim_ZECZ3ll J71:rtz4t在 Linux 源码中搜索 while(O)耳心r肝idK bfM* TVflJP4A| r* 碱 RHI刿胡咆iEi 详 imp匚f 4)冲O fl JiH s I B G-t-i匚3s口 Q舄呵H-QN小W言召三Ai1e4 pww uU jq 斗耳 Tif 1 . Dri S.:.Ir :- u -. lit IH , . -i41f1Jbe E li_L:_趴UH$*U !第4: ,r.Wpr = *.* w1 山 J,4 :-r.E tr* 1 * Al Fh# h “Vd J ll*l I 电. * - rt-Er_#LLinU inCLIji 基 “hPIWu:PMkvv 匚 羯Kflu 礼 L; 叙hgfJW w i M.frrT-+-(ur Juj uLc n i ! ; aii iL-;i_Qji.r L! -eH_B5iJcJ:4d_JrthUL_r.-i i.ir-4_#_HW .(ri.土i i lid jA3i Jflt; J.fH leJ 1 Lt-int 广 g=Ts,r. f; i 糕 EM*I4 Unui gist、j3 4户 3芹My:【s-if -bI. T, .-I I j d1|* |.HhiitLfll *和运T辽昨5,K I.r.L*t. _ BSlnt Frr. F,LL4r L iius 4*.百.U 寸 j btr Gng 町 I Etm 汕 JUk-Jp p ifTl Ll 1* JrtiuK-*-【t! 1 *_ itMlLj.nUR e,.MU, - J.yiT3UL4; i . J祉+k.M E H 肛言乍口田-斗“J -n-SnuF.耳.#.空二4 舁 1*:4* *hT|M-aE-iLK. &l dH_5 叫 4 *J.Wdy.bdJlFX: ilq= LS C_ 1._riCu-Jh. - HK_-HjczJfia_L LP-iH_i JF-u-L 4_ f . tl-tlikM: .11,., ; iL: W LeL 嚼 C-( i-dfl.lt- iVd P I ;bL14_Jt._irA-ul_iiiiuL_LLH: lI-a 4 M 袅 J.tlr AbCAth;: _fe:l._i!F-j_lM.k_.L-*4*h4 1! *1 赳匚.n fc ?4viitaBid_JtnM_cM4LiPu 4? H 1-nfldB-iH wlk bkjii- BnliiCt -J-: -0 jEr R F -月中- :l-, Emt习*甩4七目1 严 1用贮t*eVu厂冬(i.-nI =.,【M可、.llh .*_JJ- J Ilfl*:|鼻事HiLJii5K,:顶1U frLwr 讣焊叫乩 iw! i .汕舌寸 iK i L : f tT*-JbT.ki_ UU_K :jac i_* -i-TW JUd wtf、jB . *J.blUu i* J efl_VDdBb-(Ltev lAo |t _ rrilH. V)HI _ lJftJ .W1 lhL叫LlgwREBWnJ IF _b1 X j 丫片* hf*虫 P ,闻办 Ji/i iJHC; -L I ;cHnrl.q !;*.具fWCmVHstW,F 呸.* L p_jIr踞-. 1.*U * i饥土riLKJ三f7r、Mi*J vf-Jd-ltiX_r*T10 j- tfljtA驾:,_-* iri.一 岫您福%*蛛1压*-1 -lcj-.L : Lp.#S/- fjfc- L 申 J?n S ; nk,-4 .I* ., j ywr诂* ihb I ,_,., :,b-*L_vf lidgnipOgM 企 L.td_FTCJJid_l.njh_. uJi-.J - x -4. h. U.d*- ivr h i dTi c cm _e.: K4 I 4pU-I =g见哗戏耳面中p LIij-i-pnt 顼LP枢 H!JEMF-j 1L ,tle_* (I1(-ikV-M rffc.Iiiir*41i*_LhIprt;_ _J ._atiiac_fm._-clC M &言内L: iil町j rlii.cl*;f :1J- | T1rJj*、-ip. |j I *ilni*:lldj ; pHrl - rui卜.Ui.Ai曲 m J I Ii . ip-f ; i:II lUJU t : L . _ ITI Tiri;.I.TiUi._La .Lj_-ut -4 .V . HlI-k Lid “0+ Jn=i-di; 5 : Yi 、 一 .-I I h IT r VE-iMhijT i,皆区热 H I T,- T Cfs *1可见,在实际应用中,Jdowhi1e(0)用的很多。.m-BLc.n-B H :;b JM H it jr*4. L ; LJ-r *M-in iniF*-: *_-fe_-LrJ.1 . doIdr T -1X1 .#运算符与运算符这两个运算符之前也有分享过,这里顺便也提一下。#号作为一个预处理运算符,可以把记号转换成字符串。例如,如果A是一个宏形参,那么#A就是转换为字符串A的形参名。这个 过程称为字符 串化(stringizing)。以下程序演示这个过程:define ADDtA.B) PrlntftA#S =(sfcc hello_c o hello_exeE: c_testhello.exe 5+28-25 + 14 = 27F: c_test#运算符可以把两个记号组合成一个记号。以下程序演示这个过程:include XAHE(rt x # nfeline PRlMrXN(n) printfttnt n: u JIvoid itnt XMAMEfl) - 14;irt XKW1E(2 = 20;.int k3 = 3;P RItfT_XN(l;PRlhrrXN(2);PRIFfr_?CN(3;r-“#n ,一取 Jn, # n);丁言丁.-i ! J I* 二一ortritf ci p. 1曰 n只I持巾U-毗潟2八1 .;:rl nr in if- x;:1-. Q-这个运算符用得很多。如:dry_gpcir: i; i; ns* itruct pi _ide?( piniinclude :S include rtdevice.hi辱 irxEude HwiWef BSP_USIINGGPIO i .21_5T1M32_PINI ”善 _&TM32_PINI_DEFAULT I bPi UA L L tNAB GPIOB,CLK_ENABLE_J 6PIO 匚 5LK: ENAmLECLKSTMj2E ISTM3.p)(2,Ej Ei STn32PIi?iWd,E. 5)PSTM32Ei-bPE2Lt 2JGPICiECLKENA3LE3njndfi indehrcc*gipiopit!SB2匡广JI V27_57W/JE? Macro iin d 、 _ _qpIODENABLE_STM32_PIM(7; STM32PIN(B, _STH32_PI(9, _STM32 _STM32STM32 -STM32 STM32 STM32 STH32 =STrt32 -STM32 TM32 *TTO2 二 STO2 STM3213), Ci 1+)1 c. 15),OIN_OEFMJLT, fflT砂FA4ILT,4DEF AULT, 0 DEFAULT, LT, ,PMC15, PII(16, G 1)/ C. 2h PI*I(1S, Gr3), 口_DEFAULT,Jef 厂 AULT, 1 , DEFALT*SprOEFAULT.伏胖左件夹v八3的)t o c e:V dri atline 16(4 linesBBE&mUjl Ln 心店.Ep to t flpdo 二fWl”/打/index, ePI01f*epif*_CLIt_EKABLE, QPICH#fipw, ePI0_PINl_S?epio_irKle5( Nf FKJZ n WJJCrWJVTPE4PE5PE6PCI 3 PC 14 P CISPHePhipcePCIPC2PC 3SAI1_HCLK_A 盟通S S 口 FSAIlSCK.A SAI1_SD_A vbat * SD_CS OSC32IM oscaouT VSS voo oscin OSCJOOT RESET I2C_SCL I2C_S0A Gee LEO GBCKEY VSSAVREF- VREF + VDOA
展开阅读全文