Как аккуратно избегать высказываний С, теряющих правду - PullRequest
5 голосов
/ 21 января 2010

Я очень рад, что в C такие вещи являются плохим кодом:

(var_a == var_b) ? TRUE : FALSE

Однако, как лучше всего с этим справиться:

/* Header stuff */
#define INTERESTING_FLAG 0x80000000
typedef short int BOOL;

void func(BOOL);

/* Code */
int main(int argc, char *argv[])
{
        unsigned long int flags = 0x00000000;

        ... /* Various bits of flag processing */

        func(flags & INTERESTING_FLAG); /* func never receives a non-zero value
                                         * as the top bits are cut off when the
                                         * argument is cast down to a short 
                                         * int
                                         */
}

Допустимо ли (при любом значении приемлемого значения, которое вы используете) иметь (flags & FLAG_CONST) ? TRUE : FALSE?

Ответы [ 9 ]

6 голосов
/ 21 января 2010

В любом случае я бы назвал func с (flags & INTERESTING_FLAG) != 0 в качестве аргумента, указывающего, что требуется логический параметр, а не арифметический результат flags & INTERESTING_FLAG.

5 голосов
/ 21 января 2010

Я бы предпочел (flags & CONST_FLAG) != 0. Более того, используйте тип _Bool, если он у вас есть (хотя он часто маскируется под bool).

4 голосов
/ 21 января 2010

Некоторым людям это не нравится, но я пользуюсь !!.

е

!!(flags & CONST_FLAG)

(не как макрос to_bool, как кто-то предложил, просто прямо в коде).

Если бы больше людей использовали это, это не было бы замечено как необычное , поэтому начните использовать это !!

4 голосов
/ 21 января 2010

Установите флаги компилятора как можно более анально, чтобы предупредить вас о любом преобразовании, которое теряет биты, и обрабатывать предупреждения как ошибки.

1 голос
/ 21 января 2010

Возможно, это не популярное решение, но иногда полезны макросы.

#define to_bool(x) (!!(x))

Теперь мы можем безопасно получить все, что захотим, не боясь переполнить наш тип:

func(to_bool(flags & INTERESTING_FLAG));

Другой альтернативой может быть определение вашего логического типа как intmax_t (из stdint.h), чтобы невозможно было усечь значение до фальши.

Пока я здесь, я хочу сказать, что вы должны использовать typedef для определения нового типа, а не #define:

typedef short Bool; // or whatever type you end up choosing

Некоторые могут возразить, что для числовых констант следует использовать переменную const вместо макроса:

const INTERESTING_FLAG = 0x80000000;

В целом, есть вещи получше, на которые можно потратить время. Но макросы для typedef s немного глупы.

0 голосов
/ 21 января 2010

Вот почему вы должны использовать значения «логическим» способом только тогда, когда эти значения имеют явно логическую семантику. Ваше значение не удовлетворяет правилу taht, так как оно имеет ярко выраженную семантику целых чисел (или, точнее, семантику битового массива). Чтобы преобразовать такое значение в логическое значение, сравните его с 0

func((flags & INTERESTING_FLAG) != 0); 
0 голосов
/ 21 января 2010

Есть ли у вас что-нибудь против

 flags & INTERESTING_FLAG ? TRUE : FALSE

0 голосов
/ 21 января 2010

Это частично не по теме:

Я бы также создал функцию справки, которая сделает читателю понятным, какова цель проверки, чтобы вы не заполняли свой код этим явным флагом, проверяющим всюду. Определение типа флага облегчит изменение типа флага и его реализации позже.

Современные компиляторы поддерживают встроенное ключевое слово, которое может избавить от снижения производительности при вызове функции.

typedef unsigned long int flagtype;
...
inline bool hasInterestingFlag(flagtype flags) {
   return ((flags & INTERESTING_FLAG) != 0);
}
0 голосов
/ 21 января 2010

Вы можете избежать этого несколькими способами:

Сначала

void func(unsigned long int);

позаботится об этом ...

Или

if(flags & INTERESTING_FLAG)
{
  func(true);
}
else
{
  func(false);
}

также сделает это.

РЕДАКТИРОВАТЬ: (flags & INTERESTING_FLAG) != 0 тоже хорошо. Наверное, лучше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...