Почему тернарный оператор используется для определения 1 и 0 в макросе?
Я использую 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, так и кажется, что они равны. Есть причина, чтобы написать код, как они это сделали?
7 ответов:
вы правы, В С это тавтологично. Оба ваших конкретных троичных условных и
(1 > 0)
типаint
.но это б дело в C++, хотя, в некоторых любопытных угловых случаях (например, в качестве параметров для перегруженных функций), так как ваше тернарное условное выражение имеет тип
int
, тогда как(1 > 0)
типаbool
.Я предполагаю, что автор вложил в это некоторую мысль, с целью сохранения C++ совместимость.
есть пылеобразования инструменты, которые считают, что результатом сравнения является логическое значение и не могут использоваться непосредственно в арифметике.
не называть имен и показывать пальцем, но ПК-Линт-это такой инструмент пылеобразования.
Я не говорю, что они правы, но это возможное объяснение, почему код был написан так.
вы иногда будете видеть это в очень старый код, прежде чем был стандарт 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
в конце все из них, чем беспокоиться о том, какие из них действительно нужны.
в коде SDK есть ошибка, и троичный, вероятно, был kludge, чтобы исправить это.
будучи макросом, аргументы (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 '{'**
в 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 */ }
также возможно, что никакого эффекта не было запланировано, и автор просто подумал, что это сделало код более ясным.
одно простое объяснение заключается в том, что некоторые люди либо не понимают, что условие будет возвращать то же значение в C, или они думают, что это чище писать
((a>b)?1:0)
.это объясняет, почему некоторые также используют подобные конструкции в языках с правильными логическими значениями, которые в C-синтаксисе были бы
(a>b)?true:false)
.Это также объясняет, почему вы не должны без необходимости изменять этот макрос.