Использование и возврат вывода в макросе C

Я пытаюсь обработать некоторый код, чтобы ловить и печатать сообщения об ошибках. В настоящее время я использую макрос, например:

#define my_function(x) \
  switch(function(x)) { \
    case ERROR: \
      fprintf(stderr, "Error!\n"); \
      break; \
  }

Обычно я никогда не записываю вывод функции, и это работает нормально. Но я нашел пару случаев, когда мне также нужно вернуть значение function(). Я пробовал что-то вроде следующего, но это приводит к синтаксической ошибке.

#define my_function(x) \
  do { \
    int __err = function(x); \
    switch(__err) { \
      case ERROR: \
        fprintf(stderr, "Error!\n"); \
        break; \
    } \
    __err; \
  } while(0)

Я могу объявить глобальную переменную для хранения возвращаемого значения функции, но это выглядит уродливым, и моя программа многопоточна, что может вызвать проблемы. Я надеюсь, что там будет лучшее решение.

Ответ 1

Это относительно сложный код, в мастере не так много причин. Сделайте это inline (C99) или static (C89) или оба, если вы действительно хотите поместить его в файл заголовка. С любым разумным компилятором это должно привести к той же эффективности, что и макрос.

Ответ 2

GCC имеет функцию под названием оператор выражения

Так что, если определить макрос как

#define FOO(A) ({int retval; retval = do_something(A); retval;})

тогда вы сможете использовать его как

foo = FOO(bar);

Ответ 3

Очень поздний ответ. Но тем не менее. Я согласен, что встроенные функции лучше, но MACROs предлагают довольно приятную печать, которую вы не можете получить с встроенными функциями. Я согласен с @qrdl, что вы действительно можете использовать выражения выражения, если бы вы немного изменили свои утверждения. Вот как это будет работать с макросом -

#define my_function(x, y) ({ \
  int __err = 0; \
  do { \
    __err = function(x, y); \
    switch(__err) { \
      case ERROR: \
        fprintf(stderr, "Error!\n"); \
        break; \
    } \
  } while(0); \
  __err; \
})

Ответ 4

Извините, это редактирование...

  • Думаю, вам просто нужны фигурные скобки. Нет необходимости в ключах do..while.
  • Убедитесь, что обратная косая черта - последние символы в каждой строке (без пробелов).
  • Если вам нужно получить значение err из макроса, вы можете просто добавить параметр

Так же:

 #define my_function(x, out) \
      { \
        int __err = function(x); \
        switch(__err) { \
          case ERROR: \
            fprintf(stderr, "Error!\n"); \
            break; \
        } \
        __err; \
        (*(out)) = _err; \
      }

Чтобы сохранить парадигму C-pass-by-reference, вы должны вызвать my_function следующим образом:

int output_err;

my_function(num, &output_err);

Таким образом, если вы решите сделать my_function реальную функцию, вам не нужно менять ссылки на вызовы.

Btw, qrdl "Выражения выписки" также являются хорошим способом сделать это.

Ответ 5

В вашем втором выражении (строки 2 и 3) есть 2 недостающих \, это правильно?

Ответ 6

нет необходимости объявлять переменную, если ваша функция возвращает что-то, тогда вы можете напрямую получить это значение. Например:

#define FOO(A) do_something(A)

Здесь do_something возвращает некоторое целое число. Затем вы можете легко использовать его, например:

int a = FOO(a);