Можно ли использовать оператор 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 (но не так, как вы ожидаете). С #defines - это просто подстановка текста, вы должны быть очень осторожны в том, как вы ее расширяете. Я обнаружил, что это работает...

#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 ifs также (хотя, как указывали другие ответы, вероятно, проще использовать троичный оператор.)


проблема в том, что 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"); }