1.前提
本文所介绍的 “#” 操作符的三种用法均发生在预编译阶段, 这点对于理解 “#”,操作符是非常重要的。
2. 第一种用法:#include #define #if …
如下示例,这种用法是最长见的用法,在此不过多描述。
/* 头文件包含 */
#include <stdint.h>
/* 宏定义 */
#define INCLUDE_vTaskPrioritySet 1
#define INCLUDE_uxTaskPriorityGet 1
#define INCLUDE_vTaskDelete 1
/* 条件编译 */
#if ( configUSE_PREEMPTION == 0 )
#define queueYIELD_IF_USING_PREEMPTION()
#else
#if ( configNUMBER_OF_CORES == 1 )
#define queueYIELD_IF_USING_PREEMPTION() portYIELD_WITHIN_API()
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
#define queueYIELD_IF_USING_PREEMPTION() vTaskYieldWithinAPI()
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
#endif
3. 第二种用法:将宏定义的参数转化为一个字符串
通过如下示例,一看即可明白。
3.1 示例1
- 如下c示例:
#include <stdio.h> #define STRING(s) #s int main (void) { printf ("%s\n", STRING(hello)); return 0; }
- 将上面代码进行预编译:
为防止预编译后的代码太大,注释了 #include <stdio.h>gcc -E hello.c -o hello.i
# 0 "hello.c" # 0 "<built-in>" # 0 "<command-line>" # 1 "/usr/include/stdc-predef.h" 1 3 4 # 0 "<command-line>" 2 # 1 "hello.c" int main (void) { printf ("%s\n", "hello"); return 0; }
- 总结:由示例可看出,对宏参数使用 # 修饰,预编译器会将宏参数先加上 “”,然后再复制到调用位置。
与不加 # 相比,预编译器多了加 “” 的操作
3.2 示例2
如下示例是linux内核中的一句内嵌汇编,用于在c代码中插入 nop 指令,关于gcc内嵌汇编,有兴趣可以看我的另外一篇文章https://blog.youkuaiyun.com/dmf_fff/article/details/134587580
#define __nops(n) ".rept " #n "\nnop\n.endr\n"
#define nops(n) asm volatile(__nops(n))
3.2.1 .rept 和 .endr
上面代码中的 .rept 和 .endr,是一组汇编伪指令,由汇编器处理,可以看做是将 .rept 和 .endr之间的指令复制多份,有兴趣可以看汇编器手册 7.82
3.2.2 预编译示例
-
预编译前
#define __nops(n) ".rept " #n "\nnop\n.endr\n" #define nops(n) asm volatile(__nops(n)) int main (void) { asm volatile(__nops(7)); return 0; }
-
预编译后
int main (void) { asm volatile(".rept " "7" "\nnop\n.endr\n"); return 0; }
4. 第三种用法:拼接宏参数
看如下示例:
- 预编译前
#define BFQ_BFQQ_FNS(name) \ void bfq_mark_bfqq_##name(struct bfq_queue *bfqq); \ void bfq_clear_bfqq_##name(struct bfq_queue *bfqq); \ int bfq_bfqq_##name(const struct bfq_queue *bfqq); BFQ_BFQQ_FNS(just_created); BFQ_BFQQ_FNS(busy); BFQ_BFQQ_FNS(wait_request); BFQ_BFQQ_FNS(non_blocking_wait_rq); BFQ_BFQQ_FNS(fifo_expire); BFQ_BFQQ_FNS(has_short_ttime); BFQ_BFQQ_FNS(sync); BFQ_BFQQ_FNS(IO_bound); BFQ_BFQQ_FNS(in_large_burst); BFQ_BFQQ_FNS(coop); BFQ_BFQQ_FNS(split_coop); BFQ_BFQQ_FNS(softrt_update); #undef BFQ_BFQQ_FNS
- 预编译后
void bfq_mark_bfqq_non_blocking_wait_rq(struct bfq_queue *bfqq); void bfq_clear_bfqq_non_blocking_wait_rq(struct bfq_queue *bfqq); int bfq_bfqq_non_blocking_wait_rq(const struct bfq_queue *bfqq);; void bfq_mark_bfqq_fifo_expire(struct bfq_queue *bfqq); void bfq_clear_bfqq_fifo_expire(struct bfq_queue *bfqq); int bfq_bfqq_fifo_expire(const struct bfq_queue *bfqq);; void bfq_mark_bfqq_has_short_ttime(struct bfq_queue *bfqq); void bfq_clear_bfqq_has_short_ttime(struct bfq_queue *bfqq); int bfq_bfqq_has_short_ttime(const struct bfq_queue *bfqq);; void bfq_mark_bfqq_sync(struct bfq_queue *bfqq); void bfq_clear_bfqq_sync(struct bfq_queue *bfqq); int bfq_bfqq_sync(const struct bfq_queue *bfqq);; void bfq_mark_bfqq_IO_bound(struct bfq_queue *bfqq); void bfq_clear_bfqq_IO_bound(struct bfq_queue *bfqq); int bfq_bfqq_IO_bound(const struct bfq_queue *bfqq);; void bfq_mark_bfqq_in_large_burst(struct bfq_queue *bfqq); void bfq_clear_bfqq_in_large_burst(struct bfq_queue *bfqq); int bfq_bfqq_in_large_burst(const struct bfq_queue *bfqq);; void bfq_mark_bfqq_coop(struct bfq_queue *bfqq); void bfq_clear_bfqq_coop(struct bfq_queue *bfqq); int bfq_bfqq_coop(const struct bfq_queue *bfqq);; void bfq_mark_bfqq_split_coop(struct bfq_queue *bfqq); void bfq_clear_bfqq_split_coop(struct bfq_queue *bfqq); int bfq_bfqq_split_coop(const struct bfq_queue *bfqq);; void bfq_mark_bfqq_softrt_update(struct bfq_queue *bfqq); void bfq_clear_bfqq_softrt_update(struct bfq_queue *bfqq); int bfq_bfqq_softrt_update(const struct bfq_queue *bfqq);;