Неправильное использование cool
В проекте C (OpenVPN является рассматриваемым проектом, commit 4029971240b6274b9b30e76ff74c7f689d7d9750), у нас была эмуляция bool
typedef int bool;
#define false 0
#define true 1
и теперь переключитесь на C99 bool
#include <stdbool.h>
Но в проекте есть где-то плохое использование bool. Я знаю, что std bool ведет себя по-другому. Например.
bool t;
t=2;
if ( t == true)
printf("True!\n");
else
printf("False!\n");
Вернется True! с stdbool.h
и False! с эмуляцией #define
.
Мой вопрос Есть ли способ найти эти части кода, которые ведут себя по-разному с stdbool и emulated bool? Возможно, какой-то флаг компилятора я пропустил или хороший промежуточный формат llvm или gcc, который можно отличить?
Это не так просто, как в приведенном выше примере, но должно быть то, что не так просто видеть. Определенно не == true.
UPDATE:
Мы обнаружили проблему (у mbuf_set есть int member len). Это глупо, но вопрос все еще остается, как поймать их. Я удивлен, что целые проверки переполнения не улавливают такие вещи:
static inline bool
mbuf_len (const struct mbuf_set *ms)
{
return ms->len;
}
Ответы
Ответ 1
Вид использования, который вы описываете, является правильным, четко определенным поведением. Поэтому компилятор не выдаст никаких предупреждений. Один из возможных способов - изменить typedef
:
typedef enum {false, true} bool;
Это все равно позволит компиляции кода без ошибок (как он определенно), но вы можете принудительно вызывать предупреждения из компилятора или анализатора. Например, clang
будет выбирать этот тип с помощью -Weverything
:
$ clang -o a a.c -Weverything
a.c:7:11: warning: integer constant not in range of enumerated type 'bool'
[-Wassign-enum]
bool n = 2;
Конечно, это не будет проверять время выполнения. Он все равно позволит изменить переменную bool typedef
на что-то другое, кроме 0 или 1 (например, через вызов функции или выражение). Единственный способ обнаружить эти экземпляры - использовать отладчик.
Макросы для true и false в stdbool.h
предназначены только для типа _Bool
. Это связано с тем, что этот тип может содержать только значения 0 и 1; любое значение, которое вы назначаете, которое не равно 0, хранится как 1. Таким образом, для булевого типа гарантируется работа с истинными и ложными макросами.
Без типа _Bool
не существует способа, чтобы сам язык делал это для вас напрямую, потому что нет сопоставимого типа, и вы действительно попросите его разрешить, чтобы 2 == 1
возвращал true.
Существует несколько способов реализации такого же поведения, например. используя макрос, такой как BOOL(n)
в каждом случае использования переменной n
, чтобы обеспечить его значение только 0 или 1. Таким образом, вы получите тот же результат, используя _Bool
или int
для n
. Например:
#define BOOL(n) ((n) != 0 ? 1 : 0 )
bool b = rand() % 100;
if (BOOL(b) == true) ...
Это будет работать, используя stdbool
или typedef
.
Ответ 2
Извините, долго писать комментарии, так что это не ответ:
Я думаю, что вы должны искать все файлы для таких слов, как true
, false
,... и просматривать их использование.
IMO, используя автоматические инструменты, возможно, проблема с этим:
int x = true;
int y = 8;
//...
if (x == y) // `true` is not near `if` statement
{
//...
Я предпочитаю просмотр кода вручную, однако это может потребовать много времени.
Все другие предложения, такие как un-define bool
, true
, false
,..., чтобы заставить компилятор давать ошибки, являются просто сложными способами простого поиска.
Если компилятор говорит:
"у вас есть идентификатор undefined" true "в строке xyz"
ОК, инструмент поиска говорит:
"У вас есть" истинное "слово в строке zyx"
Я предпочитаю второй способ.