🕌

カーネルで使われる三項演算子

2022/10/16に公開

カーネルで使われる三項演算子

三項演算子 は英語でternary operatorsです。
A ? B: C
AがTrueならBを返し、FalseならCを返す。

通常はif文を使うため、三項演算子は使わないのですが。
カーネルでは特殊な使い方をしていますので、見ていきます。

#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;
}

初め見たとき、これは一体何がしたいのか首をかしげました。
まずAに1が設定されているため常にTrueです。
そのままbitmapを返しているだけ。

2つのことをチェックしています。
A ? B: Cですが、BとCは同じ型であることが要求されます。
bitmapは(void *)型であること。

もう一つはbitmapは (const unsigned long*)型に変換可能であること。

最後に(cpumask *)型に変換して返しています。
つまりカーネルの三項演算子は型チェックに使われます。
ソースを読むぶんには無視しても構いません。
最初からcpumaskで変数登録しておけば変換不要になると思うのだが、それは不明。

それっぽいプログラムを作成した。

#include <stdio.h>

#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;
}

unsigned long x[1];
int z;

struct cpumask {
       unsigned long bits[1]; 
};

int main()
{
     struct cpumask *y;

     x[0] = 100;
     x[1] = 200;

     y = to_cpumask(x);
     //y = to_cpumask(z); 有効にすると警告出る
     //z = to_cpumask(x); 有効にすると警告出る
     
     printf("x[0] %lu\n", x[0]);
     printf("x[1] %lu\n", x[1]);

     printf("y->bits[0] %lu\n", y->bits[0]);
     printf("y->bits[1] %lu\n", y->bits[1]);
     return 0;
}

https://stackoverflow.com/questions/61926656/what-is-the-need-of-ternary-operator-with-always-true-condition-in-linux-kernel

https://stackoverflow.com/questions/109710/how-do-the-likely-unlikely-macros-in-the-linux-kernel-work-and-what-is-their-ben?rq=1

https://linux-note.hatenablog.com/entry/to_cpumask

Discussion