Try   HackMD

你用的 bool 不是真正的 _Bool

與 Embedded Software Engineer 相關的問題,歡迎透過 Linkedin 與我聯繫
Linkedin

一開始認識的 bool

從大學的計算機概論,就知道有 bool 這個資料型態,並且老師總是教只要有記得 include 正確的 Header File 就可以使用,如下面的範例還可以知道,其中 true = 1 false = 0

#include <stdbool.h>
using namespace std;

int main()
{
    bool b1 = true;
    bool b2 = false;
    cout << b1 <<" , "<< b2;
    return 0;
}
> 1 , 0

另外 bool 也可以跟 if 搭配著使用,如下面的範例,就是一種很常見的 bool 使用方式

#include <stdbool.h>
using namespace std;

bool isEqual(int x, int y)
{
    return (x == y);
}

int main()
{
    int x = 10;
    int y = 20;
    int z = 10;
    if (isEqual(x, y))
        cout << "x is equal to y\n";
    else
        cout << "x is not equal to y\n";
    if (isEqual(x, z))
        cout << "x is equal to z\n";
    else
        cout << "x is not equal to z\n";
    return 0;
}
> x is not equal to y
> x is equal to z

因此在我踩到坑之前,我所認知的 bool

  • 只有 1 and 0
  • bool 就像是 int 一樣,是一種 Data Type

我認識的 bool 竟然不是 _Bool

有次基於現有的 Driver Code 上面要再加上支援 Suspend / Resume 的功能,因此去 #include <linux/suspend.h> ,沒想到在 Native Kernel 當中出現 Compile Error 的狀況

./include/linux/memcontrol.h:961:9: error: incompatible pointer to 
integer conversion returning 'struct mem_cgroup *' from a function with
result type 'unsigned char' [-Wint-conversion]

看 Compile Error 的訊息回去看 Source Code 是下面這段,可以看到 Return Type 是 bool 但回傳的卻是 Pointer,所以認為是發生 implicit type conversion

// the member of task_struct
struct mem_cgroup       *memcg_in_oom; 

// include/linux/memcontrol.h
static inline bool task_in_memcg_oom(struct task_struct *p)
{
    return p->memcg_in_oom;
}

還提了個 Patch 到 LKML 說明應該避免使用 implicit type conversion
[PATCH] mm: avoid implicit type conversion

C99 _Bool

信發出去馬上就有高手看出問題並且回覆如下

That makes no sense. Do you have bool (or _Bool) defined or typedefed to unsigned char somewhere? If so, that's the bug that needs to be fixed.

回頭檢視 C99 規格書對於 bool 的定義,發現真正的 Data Type 是 _Bool 並非 boolbool 應是為了 User 方便開發後續才在 Header 當中去進行 typedef。此外規格書還提到,任何值傳進去給 _Bool 都會先去做比較,值假如是 0 那就會是 0 , 否則都會是 1,這也就說明 Native Code 為什麼沒問題,假設 PointerNULL 那就會回傳 0 , 反之就傳 1

6.3.1.2 Boolean type

When any scalar value is converted to _Bool, the result is 0 if the value compares equal to 0; otherwise, the result is 1.

重新檢查 Native Kernel 當中對於 bool 的定義,確實是把 _Bool 透過 typedef 等價於 bool

// include/linux/types.h
typedef _Bool           bool;

回頭看我改的 Driver Code 上面還真的有個 Header 自行先去定義 bool,所以到這邊就可以確定是我搞烏龍,改別人的 Driver Code 之前還要先檢查他之前用的 Header or Coding 方式是否有不符合預期的地方,不然就會一直遇到類似的問題

 #ifndef bool
 #define bool                        unsigned char
 #endif