Для питань, пов'язаних з розробкою вбудованого програмного забезпечення, звертайтеся до мене через LinkedIn. LinkedIn
Початкове розуміння bool
Під час курсу з основ комп'ютерних наук в університеті я познайомився з типом даних bool
, і викладач завжди говорив, що як тільки включено правильний заголовний файл, можна його використовувати. Як показано в прикладі нижче, ми також бачимо, що true = 1
і false = 0
:
#include
using namespace std;
int main()
{
bool b1 = true;
bool b2 = false;
cout << b1 << " , " << b2;
return 0;
}
> 1 , 0
Крім того, bool
також можна використовувати разом з if
, як показано в наступному прикладі:
#include
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 дорівнює y\n";
else
cout << "x не дорівнює y\n";
if (isEqual(x, z))
cout << "x дорівнює z\n";
else
cout << "x не дорівнює z\n";
return 0;
}
> x не дорівнює y
> x дорівнює z
Тому до того, як я натрапив на проблему, моє розуміння bool
було таким:
- Він приймає лише
1
і0
bool
— це тип даних, подібний доint
Я зрозумів, що bool
, який я знаю, це не _Bool
Якось, під час додавання підтримки Suspend/Resume до існуючого драйвера, я включив ``, але несподівано отримав помилку компіляції в Native Kernel:
./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]
Розглянувши повідомлення про помилку компіляції, я повернувся до вихідного коду, де побачив, що тип повернення був bool
, але повернуте значення було вказівником. Я запідозрив, що це проблема неявного перетворення типів.
// член структури 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;
}
Після цього я надіслав патч до LKML, пояснивши, що слід уникати використання неявного перетворення типів: [PATCH] mm: avoid implicit type conversion
C99 _Bool
Після того, як я надіслав патч, експерт швидко відповів із таким спостереженням:
Це не має сенсу. Чи є у вас визначення bool (або _Bool) як unsigned char десь? Якщо так, то це помилка, яку потрібно виправити.
Переглянувши специфікацію C99 для типу bool
, я зрозумів, що справжній тип даних — це _Bool
, а не bool
. Тип bool
насправді є typedef, визначеним у заголовному файлі для зручності. Специфікація також згадує, що будь-яке значення, яке присвоюється _Bool
, буде оцінюватися; якщо значення 0, воно стає 0, в іншому випадку — 1. Це пояснює, чому у Native Code не було проблеми: якщо вказівник дорівнює NULL
, він повертає 0; в іншому випадку повертається 1.
6.3.1.2 Тип Boolean
Коли будь-яке скалярне значення перетворюється на _Bool, результат дорівнює 0, якщо значення порівнюється з 0; в іншому випадку результат дорівнює 1.
Перевіривши визначення bool
в Native Kernel, я підтвердив, що насправді він типізує _Bool
як bool
:
// include/linux/types.h
typedef _Bool bool;
Коли я повернувся до своїх змін у драйвері, я побачив, що один із заголовків явно визначав bool
, що призвело до цієї проблеми. Це підтвердило, що це була моя помилка. При зміні чужого драйвера необхідно перевіряти заголовки або стиль коду, який вони використовують, оскільки неуважність може призвести до непередбачених проблем, як у цьому випадку.
#ifndef bool
#define bool unsigned char
#endif
Перекладено з: [The bool You Use is Not the True _Bool](https://medium.com/@chao.shun.cheng.tw/the-bool-you-use-is-not-the-true-bool-33703c8501f6)