简体   繁体   English

在 Linux kernel 中始终为真条件的三元运算符需要什么?

[英]What is the need of ternary operator with always true condition in Linux kernel?

When it comes to some macro functions defined in the Linux kernel, I can find some weird ternary operator with always true condition (1)当涉及到 Linux kernel 中定义的一些宏函数时,我可以找到一些始终为真条件的奇怪三元运算符 (1)

#define to_cpumask(bitmap)                                              \
        ((struct cpumask *)(1 ? (bitmap)                                \
                            : (void *)sizeof(__check_is_bitmap(bitmap))))

static inline int __check_is_bitmap(const unsigned long *bitmap)
{
        return 1;
}

It seems that __check_is_bitmap(bitmap) function will not be invoked at any condition because it is written with ternary operator condition 1.似乎__check_is_bitmap(bitmap) function 在任何条件下都不会被调用,因为它是用三元运算符条件 1 编写的。

It seems that to check the type of bitmap at the compile time, this macro function intentionally has introduced a function, __check_is_bitmap , that requires an unsigned long pointer parameter, even though it will not be invoked.似乎为了在编译时检查 bitmap 的类型,这个宏 function 故意引入了一个 function, __check_is_bitmap ,尽管它不需要调用无符号指针。

If it wants to check the parameter type requirement, it would have been better to use an inline function or just plain function.如果要检查参数类型要求,最好使用内联 function 或简单的 function。 Why the kernel programmers prefer the #defined function compared to inline function in this case?为什么在这种情况下,与内联 function 相比,kernel 程序员更喜欢#defined function?

I am by far not an expert on kernel, with this in mind here are my two cents:到目前为止,我还不是 kernel 方面的专家,考虑到这一点,这是我的两分钱:

It looks to me like a type safety check for the macro parameter bitmap .在我看来,它像是宏参数bitmap的类型安全检查。 Since macros don't have the type safety checks of the functions, the 3rd operand of the operator is used for this purpose:由于macros没有函数的类型安全检查,因此运算符的第三个操作数用于此目的:

__check_is_bitmap(bitmap) is the operand of sizeof so it is in un unevaluated context . __check_is_bitmap(bitmap)sizeof的操作数,因此它处于未评估的上下文中 This means it is never called.这意味着它永远不会被调用。 Next, then the result of sizeof is converted to (void *) and is discarded.接下来,然后将sizeof的结果转换为(void *)并被丢弃。

This checks two things:这会检查两件事:

  • __check_is_bitmap(bitmap) is valid. __check_is_bitmap(bitmap)是有效的。 This happens if bitmap is convertible to const unsigned long *如果bitmap可转换为const unsigned long * ,则会发生这种情况

  • the type of bitmap and void * have a common type (required by the conditional operator) bitmapvoid *的类型有一个共同的类型(条件运算符需要)

If it wants to check the parameter type requirement, it would have been better to use an inline function or just plain function.如果要检查参数类型要求,最好使用内联 function 或简单的 function。 Why the kernel programmers prefer the #defined function compared to inline function in this case?为什么在这种情况下,与内联 function 相比,kernel 程序员更喜欢#defined function?

inline was prohibited in the linux kernel.在 linux kernel 中禁止inline This is explained in "Inlining in linux" from kernel.org (an article from 2006): kernel.org(2006 年的一篇文章)的“Linux 中的内联”对此进行了解释:

[in the linux kernel] We don't use the "inline" keyword because it's broken. [在 linux 内核中] 我们不使用“inline”关键字,因为它已损坏。

[...] [...]

In theory, the keyword to do this is "inline".理论上,这样做的关键字是“内联”。 In practice, this keyword is broken on newer versions of gcc.实际上,此关键字在较新版本的 gcc 上被破坏。 Current versions of gcc turned "inline" into a request (similar to the old "register" keyword), rendering it essentially useless.当前版本的 gcc 将“内联”转换为请求(类似于旧的“注册”关键字),使其基本上无用。 These versions of gcc are free to ignore any such requests to inline functions, as well as to inline functions without the keyword.这些版本的 gcc 可以自由地忽略对内联函数以及不带关键字的内联函数的任何此类请求。

The problem with this is that to be effective, inline functions must be defined in header files (since inlining is done by the compiler, not the linker, it must be done on source code not object files).这样做的问题是,为了有效,必须在 header 文件中定义内联函数(因为内联是由编译器完成的,而不是 linker,它必须在源代码上完成,而不是 ZA8CFDE6331BD49EB66AC96F8911 文件) But even when every use of a function is inlined, an unused non-inline version of the function can still be produced and linked "just in case".但是即使每次使用 function 都是内联的,仍然可以“以防万一”生产和链接 function 的未使用的非内联版本。 If multiple.c files #include the same header, this can even result in multiple non-inline versions of the same function being passed to the linker. If multiple.c files #include the same header, this can even result in multiple non-inline versions of the same function being passed to the linker.

Earlier attempts to work around this breakage by declaring functions "static inline" or "extern inline" (instructing the compiler never to emit a non-inline version of the function, breaking the build if necessary to detect when the compiler wasn't following instructions) worked for a while, but were again broken by newer releases of gcc.早期尝试通过声明函数“静态内联”或“外部内联”来解决此问题(指示编译器永远不要发出 function 的非内联版本,必要时中断构建以检测编译器何时不遵循指令) 工作了一段时间,但又被 gcc 的较新版本打破。

Modern guidelines however encourage short inline functions :然而,现代指南鼓励短的内联函数

Linux kernel coding style Linux kernel 编码风格

12) Macros, Enums and RTL 12) 宏、枚举和 RTL

Generally, inline functions are preferable to macros resembling functions.通常,内联函数优于类似函数的宏。

15) The inline disease 15) 内联病

There appears to be a common misperception that gcc has a magic “make me faster” speedup option called inline.似乎有一种普遍的误解,即 gcc 有一个名为 inline 的神奇“让我更快”加速选项。 While the use of inlines can be appropriate (for example as a means of replacing macros, see Chapter 12), it very often is not [...]虽然使用内联可能是合适的(例如,作为一种替换宏的方法,参见第 12 章),但它通常不是 [...]

A reasonable rule of thumb is to not put inline at functions that have more than 3 lines of code in them.一个合理的经验法则是不要将 inline 放在其中包含超过 3 行代码的函数中。

So it looks like __check_is_bitmap was written in the past when inline was not allowed and nobody changed it recently.所以看起来__check_is_bitmap是在过去不允许inline并且最近没有人更改它时编写的。 Note this is just speculation.请注意,这只是猜测。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM