Оцените параметр макроса только один раз - PullRequest
5 голосов
/ 31 августа 2010

В следующем коде все, что передается как retval, оценивается как заданное для каждого использования этого токена.

#define _CPFS_RETURN(commit, retval) do { \
        util_cpfs_exit(commit); \
        return retval; \
    } while (false)

#define CPFS_RETURN_BOOL(retval) do { \
        _CPFS_RETURN(retval, retval); \
    } while (false)

Например, учитывая использование CPFS_RETURN_BOOL(inode && file_truncate(inode, len));, генерируется:

do { 
    do {
        util_cpfs_exit(inode && file_truncate(inode, len));
        return inode && file_truncate(inode, len);
    } while (0);
} while (0);

Очевидно, я не хочу выполнять оператор inode && file_truncate(inode, len); более одного раза. Как я могу убедиться, что данные токены оценены перед вставкой helter-skelter?

Обновление

Полагаю, у меня есть веская причина использовать здесь макросы. Где возможно, код помещается в реальные функции (такие как util_cpfs_exit ), которые вызываются из набора макросов, которые я использую. Макросы меняются в зависимости от типа возвращаемого значения: в C ++ у меня есть явные шаблоны для обработки этого.

Ответы [ 4 ]

4 голосов
/ 31 августа 2010

Поскольку ваш макрос зависит от типа возвращаемого значения, вы можете оценить выражение возврата и сохранить его в переменной правильного типа внутри первого уровня макроса, а затем использовать эту переменную. то есть:

#define CPFS_RETURN_BOOL(retval) do { \
    bool _tmp_ = retval;
    _CPFS_RETURN(_tmp_, _tmp_); \
} while (false);

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

В вашем примере вы получите:

do {
   bool _tmp_ = inode && file_truncate(inode, len);
   do {
      util_cpfs_exit(_tmp_);
      return _tmp_;
   } while (0);
} while (0);

выглядит хорошо.

PS: в качестве идентификатора, если вы всегда используете _CPFS_RETURN косвенно через другой макрос, следуя приведенной выше модели, нет необходимости защищать его с помощью do { } while (false);. Кроме того, размещение точки с запятой после while(false) устраняет большую часть интереса к его использованию ... это может быть хорошим примером того, почему макросы C опасны и скрывают легкие ловушки. Не то, чтобы я не любил макросы, скорее наоборот. Я из (вероятно, редкого) вида людей, которые предпочли бы, чтобы макросы C были улучшены, чтобы обойти их текущие ограничения, чтобы стать действительно крутыми (и нет, шаблоны C ++ не являются улучшенными макросами, они являются чем-то совершенно другим).

2 голосов
/ 31 августа 2010

Я бы порекомендовал вам сначала оценить состояние.

т.е.

bool val = inode && file_truncate(inode, len);

Кроме этого, возможно, совет будет избегать макросов, в этом случае они кажутся ненужными, вместо этого используйте функции.

1 голос
/ 31 августа 2010

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

0 голосов
/ 31 августа 2010

Измените макрос на статическую встроенную функцию.В gcc это так же быстро, как макрос.http://gcc.gnu.org/onlinedocs/gcc/Inline.html

...