Можно ли использовать оператор if внутри #define?
Я пытаюсь сделать макрос со следующей формулой: (a^2/(a+b))*b
, и я хочу убедиться, что не будет деления на ноль.
#define SUM_A( x, y ) if( x == 0 || y == 0) { 0 } else { ( ( ( x * x ) / ( ( x ) + ( y ) ) ) * ( y ) )}
и затем я вызываю макрос внутри main:
float a = 40, b = 10, result;
result = SUM_A(a, b);
printf("%f", result);
Я попытался использовать скобки вокруг функции if, но я продолжаю получать синтаксические ошибки перед оператором if. Я также пытался использовать return, но я где-то читал, что вы не должны использовать это в определении.
Ответы
Ответ 1
Вы не можете использовать оператор if, потому что #define
интерпретируется препроцессором, а вывод будет
result=if( x == 0 || y == 0) { 0 } else { ( ( ( x * x ) / ( ( x ) + ( y ) ) ) * ( y ) )}
что является неправильным синтаксисом.
Но альтернативой является использование тернарного оператора. Измените
#define SUM_A( x, y ) ((x) == 0 || (y) == 0 ? 0 : ( ( ( (x) * (x) ) / ( ( x ) + ( y ) ) ) * ( y ) ))
Не забудьте всегда указывать свое определение между круглыми скобками, чтобы избежать синтаксической ошибки при замене.
Ответ 2
if
вводит оператор, а не выражение. Используйте оператор "тройной" (условный):
#define SUM_A(x, y) (((x) == 0 || (y) == 0)? 0: ((((x) * (x)) / ((x) + (y))) * (y)))
В качестве альтернативы сделайте это inline
функцией:
inline float sum_a(float x, float y)
{
if (x == 0 || y == 0)
return 0;
else
return ((x * x) / (x + y)) * y;
}
Это позволяет избежать проблемы множественной оценки x
и/или y
и гораздо более читабельна, но она фиксирует типы x
и y
. Вы также можете удалить inline
строку и позволить компилятору решить, стоит ли делать эту функцию полезной (inline
функция не гарантирует, что она будет выполнять inlining).
Ответ 3
Технически можно использовать операторы if
в #define
(но не так, как вы ожидали). Поскольку #define
- это просто замена текста, вы должны быть очень осторожны, как вы его расширяете. Я обнаружил, что это работает...
#define SUM_A(x, y) \
({ \
double answer; \
if ((x) == 0 || (y) == 0) \
answer = 0; \
else \
answer = ((double)((x)*(x)) / ((x)+(y))) * (y); \
(answer); \
})
// Typecasting to double necessary, since int/int == int in C
Это должно дать вам результат, который вы ищете, и нет причин, по которым он не может быть расширен, чтобы включить в него несколько else if
(хотя, как указывали другие ответы, возможно, проще использовать тернарный оператор).
Ответ 4
Проблема в том, что оператор if
не является выражением и не возвращает значение. Кроме того, нет веских оснований для использования макроса в этом случае. На самом деле это может привести к очень серьезным проблемам с производительностью (в зависимости от того, что вы передаете в качестве аргументов макроса). Вместо этого вы должны использовать функцию.
Ответ 5
Есть несколько проблем с вашим макросом:
-
он расширяется до утверждения, поэтому вы не можете использовать его как выражение
-
аргументы в расширении не указаны в скобках: вызов этого макроса с чем-либо, кроме имен переменных или констант, вызовет проблемы.
-
аргументы оцениваются несколько раз: если вы вызываете макрос с аргументами, которые имеют побочные эффекты, такие как SUM_A(a(), b())
или SUM_A(*p++, 2)
, побочный эффект будет происходить несколько раз.
Чтобы избежать всех этих проблем, используйте функцию, определенную как static inline
чтобы оптимизировать компилятор (это необязательно, и современные компиляторы делают это автоматически):
static inline int SUM_A(float x, float y) {
if (x == 0 || y == 0)
return 0;
else
return x * x / (x + y) * y;
}
Заметки:
- эта функция использует арифметику с плавающей запятой, которую макрос не обязательно, в зависимости от фактических типов ее аргументов.
- тест не предотвращает деление на ноль: SUM_A (-1, 1) все еще выполняет одно.
- деление на ноль не обязательно является проблемой: с аргументами с плавающей запятой он создает бесконечность или NaN, а не ошибку времени выполнения.
Ответ 6
ДА, вы можете иметь оператор if в макросе. Вам нужно отформатировать его правильно. Вот пример:
#define MY_FUNCTION( x ) if( x ) { PRINT("TRUE"); } else { PRINT("FALSE"); }