在我的C代码中,我需要检查我的内核版本并根据它行事。 在makefile中,我有以下内容:
KERNEL_MAJOR :=$(word 1, $(subst ., ,$(KERNEL_HEADERS)))
KERNEL_MINOR :=$(word 2, $(subst ., ,$(KERNEL_HEADERS)))
KERNEL_MICRO :=$(word 1, $(subst -, ,$(word 3, $(subst ., ,$(KERNEL_HEADERS)))))
KERNEL_PATCH_LEVEL :=$(word 1, $(subst ., ,$(word 2, $(subst -, ,$(KERNEL_HEADERS)))))
KARGS := KCPPFLAGS="-DKERNEL_MAJOR=$(KERNEL_MAJOR) -DKERNEL_MINOR=$(KERNEL_MINOR) -DKERNEL_MICRO=$(KERNEL_MICRO) -DKERNEL_PATCH_LEVEL=$(KERNEL_PATCH_LEVEL)"
样品:
3.0.101-0.47.71-default 如下所示:
KCPPFLAGS="-DKERNEL_MAJOR=3 -DKERNEL_MINOR=0 -DKERNEL_MICRO=101 -DKERNEL_PATCH_LEVEL=0"
4.1.21.x86_64.1 (请注意KERNEL_PATCH_LEVEL):
KCPPFLAGS="-DKERNEL_MAJOR=4 -DKERNEL_MINOR=1 -DKERNEL_MICRO=21 -DKERNEL_PATCH_LEVEL="
我的代码中有宏来检查内核是否为3.0.101.0或3.0.76.0:
#if defined(KERNEL_MAJOR) && defined(KERNEL_MINOR) && defined(KERNEL_MICRO) && defined(KERNEL_PATCH_LEVEL) && \
(KERNEL_VERSION(KERNEL_MAJOR,KERNEL_MINOR,KERNEL_MICRO) == KERNEL_VERSION(3,0,101) || KERNEL_VERSION(KERNEL_MAJOR,KERNEL_MINOR,KERNEL_MICRO) == KERNEL_VERSION(3,0,76)) \
&& (KERNEL_PATCH_LEVEL == 0)
有3&&布尔表达式,如果表达式#1没问题,那么我想继续表达#2,如果表达式#2继续,我将继续表达#3。 当我尝试在内核版本4.1.21.x86_64.1上编译(make ..)时,我收到:
error: operator '==' has no left operand
这是因为 -DKERNEL_PATCH_LEVEL =“ - 请参阅输出。
我希望制作可以阻止我进入那个&&因为表达式#2失败(3.0.101或3.0.76)
答案 0 :(得分:1)
如果您阅读:https://gcc.gnu.org/onlinedocs/gcc-3.0.2/cpp_4.html,您会发现:
`#if'指令允许您测试算术表达式的值,而不仅仅是存在一个宏。它的语法是
#if 表达 ...
表达式是整数类型的C表达式,受到严格的限制。它可能包含:
...
宏。 表达式中的所有宏在表达式值的实际计算开始之前都会展开。
不是宏的标识符,它们都被认为是数字零。 ...
所以如果你有:
#if defined(FOO) && FOO == 1
然后没有定义foo,它会将表达式解析为:
0 && 0 == 1
然后将解析为#if 0
,这是有效的。但是,如果您将FOO
定义为空白,则它将解析为:
1 && == 1
然后预编译器将尝试解析表达式,并获得语法错误,并失败。尽管网上似乎有一些评论,但预编译器并没有将表达式的解析短路,只是表达式的评估。
如果您想解决这个问题,可以使用以下宏观技巧:
#define COMBINE1(W,Y,Z) W##Y##Z
#define COMBINE(W,Y,Z) COMBINE1(W,Y,Z)
#define ISEMPTY(val) COMBINE(val,4,val) == 4
#if defined FOO
#if ISEMPTY(FOO)
#pragma message "FOO DEFINED AS EMPTY"
#else
#pragma message "FOO DEFINED (NOT EMPTY)"
#endif
#else
#pragma message "FOO NOT DEFINED"
#endif
给出:
~/sandbox/tst6> gcc tst2.c
tst2.c:12: note: #pragma message: FOO NOT DEFINED
~/sandbox/tst6> gcc tst2.c -DFOO=
tst2.c:7: note: #pragma message: FOO DEFINED AS EMPTY
~/sandbox/tst6> gcc tst2.c -DFOO=1
tst2.c:9: note: #pragma message: FOO DEFINED (NOT EMPTY)
答案 1 :(得分:1)
你是正确的相信C预处理器,就像C编译器一样,
执行&&
- 和||
- 表达式的短路评估。
但是,与编译器不同,你认为预处理器是错误的, 可以对无意义的令牌序列进行“短路”评估, 只要废话处于上下文之一:
TRUE || [nonsense]
或
FALSE && [nonsense]
就像编译器一样,预处理器可以评估的任何序列 表达式,短路与否,必须是(格式良好的)表达, 这
FALSE && ( == 0)
不是。
答案 2 :(得分:0)
所有#if
条件都已通过,因为KERNEL_PATCH_LEVEL
已定义。它只是被定义为一个空字符串。 -DKERNEL_PATCH_LEVEL=
相当于
#define KERNEL_PATCH_LEVEL
当然,will pass an #if (defined)
test。
它somewhat difficult来测试宏是否为空。如果版本字符串中没有特殊值(如0或-1),修改makefile以定义KERNEL_PATCH_LEVEL
可能更容易。