灵活使用 C 语言中的宏定义

最近在看内核中 qspinlock相关的代码,发现了一些有意思的实现,尤其是在 kernel/locking/qspinlock.c文件的最后几行,通过 #include "qspinlock.c"语句又把这个 C文件的内容包含了进来,但前提是在 #include之前把某些关键的宏定义改了,这就使得在处理新包含进来的文件内容时,能够得到与上面第一次处理时不一样的结果,这在很大程度上复用了代码。

下面通过一个简化版的例子来展示上述实现的细节:
首先定义 file.c文件,它的实现类似于上述 kernel/locking/qspinlock.c文件:

#ifndef _GEN_PV_LOCK_SLOWPATH

#include <stdbool.h>
#include <stdio.h>
#include "file.h"

static void __pv_init_node(void)
{
	printf("dummy\n");
}

#define pv_enabled()        false

#define pv_init_node        __pv_init_node

#ifdef CONFIG_PARAVIRT_SPINLOCKS
#define queued_spin_lock_slowpath   native_queued_spin_lock_slowpath
#endif

#endif /* _GEN_PV_LOCK_SLOWPATH */

EXPORT_SYMBOL(queued_spin_lock_slowpath);
void queued_spin_lock_slowpath(void)
{
	if (pv_enabled()) {
		printf("pv enabled\n");
	} else {
		printf("pv not enabled\n");
	}

	pv_init_node();
	printf("symbol of this function: %s\n", SYMBOL_NAME(queued_spin_lock_slowpath));
}

#if !defined(_GEN_PV_LOCK_SLOWPATH) && defined(CONFIG_PARAVIRT_SPINLOCKS)
#define _GEN_PV_LOCK_SLOWPATH

#undef  pv_enabled
#define pv_enabled()    true

#undef pv_init_node
void pv_init_node(void)
{
	printf("not dummy\n");
}

#undef queued_spin_lock_slowpath
#define queued_spin_lock_slowpath   __pv_queued_spin_lock_slowpath

#include "file.c"

#endif

再定义与之配套的 file.h文件

#ifndef _FILE_H_
#define _FILE_H_

#define SYMBOL_NAME(name) __SYMBOL_NAME(name)
#define __SYMBOL_NAME(name) __sym_##name

#define DECLARE_SYMBOL(name) char *SYMBOL_NAME(name)

#define EXTERN_SYMBOL(name) extern DECLARE_SYMBOL(name)

#define __EXPORT_SYMBOL(name) \
	DECLARE_SYMBOL(name) = #name

#define EXPORT_SYMBOL(name) __EXPORT_SYMBOL(name)

#endif

最后定义 main.c文件

#include <stdio.h>
#include "file.h"

#ifdef CONFIG_PARAVIRT_SPINLOCKS
EXTERN_SYMBOL(native_queued_spin_lock_slowpath);
EXTERN_SYMBOL(__pv_queued_spin_lock_slowpath);
#else
EXTERN_SYMBOL(queued_spin_lock_slowpath);
#endif

void test(void)
{
#ifdef CONFIG_PARAVIRT_SPINLOCKS
	native_queued_spin_lock_slowpath();
	printf("=========================================================\n");
	__pv_queued_spin_lock_slowpath();
#else
	queued_spin_lock_slowpath();
#endif
}

int main(void)
{
	test();

	return 0;
}

下面通过 CONFIG_PARAVIRT_SPINLOCKS宏来展示两种不同的用法。

如果不定义 CONFIG_PARAVIRT_SPINLOCKS宏,相当于 queued_spin_lock_slowpath()只有一种实现: 即native_queued_spin_lock_slowpath()
而如果定义了 CONFIG_PARAVIRT_SPINLOCKS宏,相当于 queued_spin_lock_slowpath()有两种实现:即native_queued_spin_lock_slowpath()__pv_queued_spin_lock_slowpath()

用法一:不定义 CONFIG_PARAVIRT_SPINLOCKS
运行结果如下所示:

$ gcc -o main main.c file.c -I./ 
$ ./main 
pv not enabled
dummy
symbol of this function: queued_spin_lock_slowpath

用法二:定义CONFIG_PARAVIRT_SPINLOCKS
运行结果如下所示:

$ gcc -o main main.c file.c -I./ -DCONFIG_PARAVIRT_SPINLOCKS
$ ./main 
pv not enabled
dummy
symbol of this function: native_queued_spin_lock_slowpath
=========================================================
pv enabled
not dummy
symbol of this function: __pv_queued_spin_lock_slowpath
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值