|
[导读] 嵌入式er编程,一些常见的宏应该掌握如何去使用,会带给你很多有用的功能。关于标准定义宏的详细示例,见今天推送的第二篇转载文章,总结的很清晰。本文特别示例了一下如何利用日期时间宏自动内置编译时间信息进入固件。 标准预定义宏
使用示例: fprintf (stderr, "Internal error: ""negative string length " "%d at %s, line %d.", length, __FILE__, __LINE__); 其他详细的示例可以阅读今日第二篇转载文章,总结的很清晰很详细,这里不重复了。 系统预定义宏不同的编译器或不同的硬件体系结构会定义一些系统相关的预定义宏,以IAR for ARM为例:
如何查看宏是否被预定义呢,我们可以查看编译器手册,除此之外,也可以用如下的方式进行预处理提示:& E; Z i, |; [
两者的语法一样,如下: #error "message" #warning "message" 如: /*或 error 打印提示,但编译会停止*/, ?$ S% P V" i6 Y0 K#ifdef __AAPCS__7 C2 G# b+ P+ Q3 L #error “__AAPCS__ has been defined"1 m8 j9 d; B8 L. r0 v( G y6 U #endif /*或 warning 打印提示,但编译会继续*/" N" |3 o m. [( e #ifdef __AAPCS__7 e# W Y1 g8 c) L #warning “__AAPCS__ has been defined"- i) b& e& [1 A2 @5 C7 a #endif 又比如GNU C,还定义了大量的扩展内置宏,比如:
#undef 可以取消已定义的宏,比如: #ifdef TRUE#undef TRUE+ C/ s1 k* s8 r* M, W #endif$ n. `& Y$ \8 m. t7 C #define TRUE 1 这样做的意义是什么呢?前面已定义了,这里又把它取消掉且再重定义,骚操作?这是有意义且有实用价值的。因为宏是按照包含关系层层展开的,本质是编译之前的文本替换。这样就可以明确指定宏在某些部位是确定的值,因为多人协调开发,或者使用别的开发包或者开发环境,有的宏已经被定义过了,如果不做此处理,这样宏值很可能不是你想要的值。 这里再强调一下:宏的本质是编译器之前的文本替换,这也是预编译的最重要任务之一* x- X0 [$ A. c/ n 项目开发发布的固件,经常会需要将版本信息、编译时间信息内置在固件中,可能涉及的应用需求:
这时就可以直接使用 __DATE__, __TIME__实现将编译时间自动编译进发布的固件中。示例代码如下: /*IAR for ARM 8.4为例*/#include <stdio.h>2 P2 T8 M# e) ]( T% F ! v& W5 W8 j8 k4 Z #define FW_VERSION "1.0.0"& l7 D" S' ]6 m4 X* @' e) I! q const char *firmwareInf[]={. ?9 ^1 _5 _6 p6 D {__DATE__}, {__TIME__},' x- l# U1 Q+ z {FW_VERSION}; P+ H4 I, {0 C1 X };0 E$ ^. u9 P, n" R8 Z , h; r9 e8 a) V4 @) g int main(void) { printf("Compile Time:%s %s \nFw version:%s\n",firmwareInf[0],firmwareInf[1],firmwareInf[2]);3 h- r: f. R$ H% P: u( Z while (1)1 h, \8 N" q; G' x7 j' p5 E { } } 来看下疗效:
延伸思考,还可以将firmwareInf常量字符串放入一个确定存储位置,这就需要利用链接器脚本来指定存储位置。 宏的使用在C语言中有极高的价值,如果阅读u-boot以及Linux内核代码,你会发现大量的复杂应用,所以有必要先将这些基础的宏应用熟练掌握。 |
微信公众号
手机版