Использование и возврат вывода в макросе C - PullRequest
10 голосов
/ 20 августа 2010

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

#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)

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

Ответы [ 5 ]

47 голосов
/ 20 августа 2010

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

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

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

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

foo = FOO(bar);
6 голосов
/ 20 августа 2010

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

4 голосов
/ 02 февраля 2016

Очень поздний ответ.Но тем не менее.Я согласен, что встроенные функции лучше, но MACRO предлагают довольно приятное удовольствие от печати, которое невозможно получить с помощью встроенных функций.Я согласен с @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; \
})
2 голосов
/ 20 августа 2010

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

  1. Я думаю, тебе просто нужны фигурные скобки. Нет необходимости в ключевых словах do.. while
  2. Убедитесь, что обратные слэши являются последними символами в каждой строке (без пробела).
  3. Если вам нужно получить значение ошибки из макроса, вы можете просто добавить параметр

Вот так:

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

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

int output_err;

my_function(num, &output_err);

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

Кстати, «выражения выражений» qrdl также являются хорошим способом сделать это.

0 голосов
/ 24 февраля 2015

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

#define FOO(A) do_something(A)

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

int a = FOO(a);
...