Можно ли использовать оператор 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, но я где-то читал, что вы не должны использовать это в define.
6 ответов
вы не можете использовать оператор 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 ) ))
не забудьте всегда ставить свое определение между скобками, чтобы избежать синтаксической ошибки при замене.
if
вводит оператор, а не выражение. Используйте "троичный" (условный оператор):
#define SUM_A(x, y) (((x) == 0 || (y) == 0)? 0: ((((x) * (x)) / ((x) + (y))) * (y)))
в качестве альтернативы, сделайте это :
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
- это не гарантия что он будет выполнять подстановку).
технически, можно использовать if
заявления в #define
(но не так, как вы ожидаете). С #define
s - это просто подстановка текста, вы должны быть очень осторожны в том, как вы ее расширяете. Я обнаружил, что это работает...
#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
s также (хотя, как указывали другие ответы, вероятно, проще использовать троичный оператор.)
проблема в том, что if
оператор не является выражением и не возвращает значение. Кроме того, в этом случае нет веских причин использовать макрос. Фактически, это может вызвать очень серьезные проблемы с производительностью (в зависимости от того, что вы передаете в качестве аргументов макроса). Вместо этого следует использовать функцию.
есть несколько проблем с вашим макрос:
он расширяется до оператора, поэтому вы не можете использовать его в качестве выражения
аргументы неправильно заключены в скобки в расширении: вызов этого макроса с чем-либо, кроме имен переменных или констант, приведет к проблемам.
аргументы оцениваются несколько раз: если вы вызываете макрос с аргументами, имеющими побочные эффекты, такие как
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, а не ошибку времени выполнения.
YES вы можете иметь оператор if в макросе. Его нужно правильно отформатировать. Вот пример:
#define MY_FUNCTION( x ) if( x ) { PRINT("TRUE"); } else { PRINT("FALSE"); }