Я использую SDK для встроенного проекта. В этом исходном коде я нашел код, который, по крайней мере, мне показался странным. Во многих местах в SDK есть исходный код в таком формате:
#define ATCI_IS_LOWER( alpha_char ) ( ( (alpha_char >= ATCI_char_a) && (alpha_char <= ATCI_char_z) ) ? 1 : 0 )
#define ATCI_IS_UPPER( alpha_char ) ( ( (alpha_char >= ATCI_CHAR_A) && (alpha_char <= ATCI_CHAR_Z) ) ? 1 : 0 )
Имеет ли значение использование тернарного оператора здесь?
Не
#define FOO (1 > 0)
такой же как
#define BAR ( (1 > 0) ? 1 : 0)
?
Я попытался оценить это, используя
printf("%d", FOO == BAR);
и получаем результат 1, значит кажется, что они равны. Есть ли причина писать код, как они?
c++
c
boolean
ternary-operator
Виктор С
источник
источник
(alpha_char)
вместоalpha_char
, просто чтобы убедиться, что он не сломается, если кто-то попробует что-то безумноеATCI_IS_LOWER(true || -1)
.boolean
тип, так что я впустую невыразимое время изменения ужасов , какif (n)
кif (0 != n)
, возможно добавлением сомнительной слепок « чтобы убедиться , что». Я уверен, что пуленепробиваемое неравенство мнеif (a < b) ...
тоже нравится . Конечно, это было похоже на Паскаляif a < b then ...
, но я знал, что C -<
это не a,boolean
а anint
, а anint
может быть почти любым ! Страх ведет к позолоте, позолота приводит к паранойе, паранойя приводит к ... подобному коду.Ответы:
Вы правы, в C тавтологично. Обе ваши конкретные тернарные условные и
(1 > 0)
имеют типint
.Но в C ++ это имело бы значение в некоторых любопытных угловых случаях (например, в качестве параметров для перегруженных функций), поскольку ваше тернарное условное выражение имеет тип
int
, тогда как(1 > 0)
имеет типbool
.Я предполагаю, что автор задумался над этим, чтобы сохранить совместимость с C ++.
источник
bool <-> int
преобразования неявны в C ++ согласно §4.7 / 4 из стандарта (интегральное преобразование), так какое это имеет значение?foo
, одна из которых принимаетconst bool&
другойconst int&
. Один из них вам платит, другой переформатирует ваш жесткий диск. В этом случае вы можете убедиться, что вызываете правильную перегрузку.int
а не с использованием троичного?Существуют инструменты линтинга, которые считают, что результат сравнения является логическим и не может использоваться непосредственно в арифметике.
Не называть имен и не указывать пальцем, но PC-lint - такой инструмент для линтинга .
Я не говорю, что они правы, но это возможное объяснение того, почему код был написан именно так.
источник
Not to name names or point any fingers,
но ты вроде как сделал и то, и другое, лол.Иногда вы увидите это в очень старом коде, еще до того, как появился стандарт C, который
(x > y)
оценивает числовые значения 1 или 0; некоторые процессоры предпочли бы вместо этого вычислять -1 или 0, а некоторые очень старые компиляторы могли просто последовать их примеру, поэтому некоторые программисты посчитали, что им нужна дополнительная защита.Иногда вы также видите это, потому что аналогичные выражения не обязательно оцениваются как числовые 1 или 0. Например, в
#define GRENFELZ_P(flags) (((flags) & F_DO_GRENFELZ) ? 1 : 0)
внутреннее
&
-выражение оценивается либо как 0, либо как числовое значениеF_DO_GRENFELZ
, которое, вероятно, не равно 1, поэтому? 1 : 0
служит для его канонизации. Я лично считаю, что проще написать это как#define GRENFELZ_P(flags) (((flags) & F_DO_GRENFELZ) != 0)
но разумные люди могут не согласиться. Если бы у вас была целая куча таких выражений подряд, тестируя различные виды выражений, кто-то мог бы решить, что удобнее было бы положить
? 1 : 0
конец всем из них, чем беспокоиться о том, какие из них действительно нуждаются в этом.источник
!!( expr )
для канонизации логического значения, но признаю, что это сбивает с толку, если вы с ним не знакомы.В коде SDK есть ошибка, и тройка, вероятно, была кладжем для ее исправления.
В качестве макроса аргументы (alpha_char) могут быть любым выражением и должны быть заключены в круглые скобки, потому что такие выражения, как 'A' && 'c' не пройдут проверку.
#define IS_LOWER( x ) ( ( (x >= 'a') && (x <= 'z') ) ? 1 : 0 ) std::cout << IS_LOWER('A' && 'c'); **1** std::cout << IS_LOWER('c' && 'A'); **0**
Вот почему всегда следует заключать в скобки аргументы макроса в раскрытии.
Итак, в вашем примере (но с параметрами) они оба ошибаются.
#define FOO(x) (x > 0) #define BAR(x) ((x > 0) ? 1 : 0)
Правильнее всего их заменить на
#define BIM(x) ((x) > 0)
@CiaPan Обращает внимание на то, что следующий комментарий состоит в том, что использование параметра более одного раза приводит к неопределенным результатам. Например
#define IS_LOWER( x ) (((x) >= 'a') && ((x) <= 'z')) char ch = 'y'; std::cout << IS_LOWER(ch++); **1** **BUT ch is now '{'**
источник
IS_LOWER(++ var)
может увеличиватьсяvar
один или два раза, кроме того, он может не заметить и не распознать нижний регистр,'z'
если онvar
был'y'
до вызова макроса. Вот почему следует избегать таких макросов или просто передавать аргумент функции.В C это не имеет значения. Логические выражения в C имеют тип
int
и значение, равное0
или1
, поэтомуConditionalExpr ? 1 : 0
не имеет никакого эффекта.
В C ++ это фактически преобразование
int
, потому что условные выражения в C ++ имеют типbool
.#include <stdio.h> #include <stdbool.h> #ifndef __cplusplus #define print_type(X) _Generic(X, int: puts("int"), bool: puts("bool") ); #else template<class T> int print_type(T const& x); template<> int print_type<>(int const& x) { return puts("int"); } template<> int print_type<>(bool const& x) { return puts("bool"); } #endif int main() { print_type(1); print_type(1 > 0); print_type(1 > 0 ? 1 : 0); /*c++ output: int int int cc output: int bool int */ }
Также возможно, что никакого эффекта не предполагалось, и автор просто подумал, что это сделало код более понятным.
источник
_Bool
, теперь, когда у C есть_Bool
и_Generic
. Это не должно нарушать большой объем кода, учитывая, что все меньшие типыint
в любом случае автоматически продвигаются в большинстве контекстов.Одно простое объяснение состоит в том, что некоторые люди либо не понимают, что условие вернет такое же значение в C, либо думают, что писать проще
((a>b)?1:0)
.Это объясняет, почему некоторые также используют подобные конструкции в языках с правильными логическими значениями, которые в C-синтаксисе были бы такими
(a>b)?true:false)
.Это также объясняет, почему вам не следует менять этот макрос без необходимости.
источник
Может быть, будучи встроенным программным обеспечением, это даст некоторые подсказки. Может быть, есть много макросов, написанных с использованием этого стиля, чтобы легко намекнуть, что строки ACTI используют прямую логику, а не инвертированную логику.
источник