1 背景
最近开发新模块的驱动,看了下大佬提交的代码(封装给我用),每个寄存器读写通过宏函数封装实现的API。另外,我们的Linux内核中很多的函数也是通过宏函数定义的。按照其格式修改下,大致如下,:
/*寄存器定义*/
typedef struct{
unsigned int rx_en : 1 ;
unsigned int a : 1 ;
unsigned int b : 2 ;
unsigned int c : 1 ;
unsigned int d : 1 ;
unsigned int e : 3 ;
unsigned int f : 7 ;
unsigned int g : 14 ;
unsigned int h : 2 ;
} __attribute__ ((packed)) Reg_ModuleRxCfg;
/*
*SET_MODULE_RX_ENABLE(_en) RX使能宏函数写接口
*GET_MODULE_RX_ENABLE() RX使能宏函数读接口
*MODULE_REG_READ、MODULE_REG_WRITE寄存器读写
*/
#define SET_MODULE_RX_ENABLE(_en)\
do {Reg_ModuleRxCfg __c = {0};\
MODULE_REG_READ(MODULE_RX_CFG, (unsigned int *)&__c);\
__c.rx_en = !!_en;\
MODULE_REG_WRITE(MODULE_RX_CFG, *((unsigned int *)&__c));\
}while(0)
#define GET_MODULE_RX_ENABLE()\
({ Reg_ModuleRxCfg __c1 = {0}; unsigned int __c;\
MODULE_REG_READ(MODULE_RX_CFG, (unsigned int *)&__c);\
memcpy((void*)&__c1, (void*)&__c, sizeof(unsigned int));\
__c1.rx_en;\
})
/*
*接口使用
*/
SET_MODULE_RX_ENABLE(1);
unsigned char RxEnable = 0;
RxEnable = GET_MODULE_RX_ENABLE();
接口使用处,写寄存器还好理解,但是读就不好理解了,宏函数返回值是什么
2宏函数返回值
接下来就来一看究竟。
直接仿照写段代码,跑一下:
#include <stdio.h>
#define REGREAD(_DAYOFWEEK_)\
({\
char* str;\
switch (_DAYOFWEEK_){\
case 1:\
case 2:\
case 3:\
case 4:\
case 5:\
str = "小伙子,好好上班!";\
break;\
case 6:\
case 7:\
str = "小伙子,来加个班呀!";\
break;\
default:\
str = "小伙子,今年过年别回家了,加个班吧!";\
}\
(str);\
})\
int main() {
int i;
char* str;
for(i = 0; i <= 7; i++){
str = REGREAD(i);
printf("%s\n", str);
}
return 0;
}
跑一下:
从输出可以看出:
宏函数的返回值,即宏函数中最后一个表达式的值;宏函数的返回值的类型,是最后一个表达式的类型。
3 汇编查看
gcc -S macro_return.c -o macro_return.s
.file "macro_return.c"
.text
.section .rodata
.LC0:
.string "\345\260\217\344\274\231\345\255\220\357\274\214\345\245\275\345\245\275\344\270\212\347\217\255\357\274\201"
.align 8
.LC1:
.string "\345\260\217\344\274\231\345\255\220\357\274\214\346\235\245\345\212\240\344\270\252\347\217\255\345\221\200\357\274\201"
.align 8
.LC2:
.string "\345\260\217\344\274\231\345\255\220\357\274\214\344\273\212\345\271\264\350\277\207\345\271\264\345\210\253\345\233\236\345\256\266\344\272\206,\345\212\240\344\270\252\347\217\255\345\220\247\357\274\201"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $32, %rsp
movl $0, -4(%rbp)
jmp .L2
.L7:
cmpl $0, -4(%rbp)
jle .L3
cmpl $5, -4(%rbp)
jle .L4
cmpl $7, -4(%rbp)
jg .L3
jmp .L9
.L4:
movq $.LC0, -16(%rbp)
jmp .L6
.L9:
movq $.LC1, -16(%rbp)
jmp .L6
.L3:
movq $.LC2, -16(%rbp)
.L6:
movq -16(%rbp), %rax
movq %rax, -24(%rbp)
movq -24(%rbp), %rax
movq %rax, %rdi
call puts
addl $1, -4(%rbp)
.L2:
cmpl $7, -4(%rbp)
jle .L7 /*jle:条件转移指令。小于或等于,或者不大于则转移*/
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (GNU) 8.3.1 20190507 (Red Hat 8.3.1-4)"
.section .note.GNU-stack,"",@progbits
有点乱,简单分析下:
- 1、从
main
函数开始,进入.L2
再到.L7
,在.L7
中进行for循环和判断
- 2、
.L4、.L9、.L3
是switch中对应不同case的标签,可以看出.LC0:、.LC1:、.LC2:
中的字符串放到了寄存器-16(%rbp)
- 3、最后在
.L6:
中进行处理,并调用了puts函数,将字符串输出。
从汇编也可以看出,输出的是最后一个表达式的值。