Есть макрос "вернуть" значение - PullRequest
18 голосов
/ 21 апреля 2010

Я использую макрос и думаю, что он отлично работает -

#define CStrNullLastNL(str) {char* nl=strrchr(str,'\n'); if(nl){*nl=0;}}

Таким образом, он работает для обнуления последней новой строки в строке, на самом деле он используется, чтобы отрубить разрыв строки, когда он оставлен fgets.

Итак, мне интересно, смогу ли я "вернуть" значение из макроса, чтобы оно могло называться как

func( CStrNullLastNL( cstr ) ) ;

Или мне придется написать функцию

Ответы [ 8 ]

30 голосов
/ 21 апреля 2010

Чтобы макрос «возвратил значение», сам макрос должен быть выражением.Ваш макрос - это блок операторов, который не может быть преобразован в выражение.

Вы действительно должны написать функцию inline.Это будет так же быстро и гораздо более легко обслуживаемо.

24 голосов
/ 21 апреля 2010
#define CStrNullLastNL(str) ({ \
    char* nl=strrchr(str,'\n');\
    if(nl){*nl=0;} \
    nl; \
})

должно работать.

Редактировать: ... в GCC.

5 голосов
/ 21 апреля 2010

Макрос не возвращает значения. Макросы говорят препроцессору заменять все, что находится после #define, на то, что следует после #define. Результат должен быть действительным C ++.

То, что вы просите, это как сделать следующее действительным:

func( {char* nl=strrchr(str,'\n'); if(nl){*nl=0;}} );

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

4 голосов
/ 21 апреля 2010

Можете ли вы использовать оператор запятой? Упрощенный пример:

#define SomeMacro(A) ( DoWork(A), Permute(A) )

Здесь B = SomeMacro (A) «возвращает» результат Permute (A) и присваивает его «B».

4 голосов
/ 21 апреля 2010

Если вы действительно хотите это сделать, получите компилятор, который поддерживает лямбды в стиле C ++ 0x:

#define CStrNullLastNL(str) [](char *blah) {char* nl=strrchr(blah,'\n'); if(nl){*nl=0;} return blah;}(str)

Хотя, поскольку CStrNullLastNL в основном функция, вам, вероятно, следует переписать ее как функцию.

3 голосов
/ 24 февраля 2017

Если у вас нет строгого требования использовать только макрос, вы можете сделать что-то вроде этого (пример из реальной жизни):

#define Q_XCB_SEND_EVENT_ALIGNED(T) \
    q_xcb_send_event_aligned<T>()

template<typename T> inline
T q_xcb_send_event_aligned()
{
    union {
        T event;
        char padding[32];
    } event;

    memset(&event, 0, sizeof(event));
    return event.event;
}

А затем используйте его в своем коде так:

auto event = Q_XCB_SEND_EVENT_ALIGNED(xcb_unmap_notify_event_t);
3 голосов
/ 21 апреля 2010

Я дал +1 Майку, потому что он на 100% прав, но если вы хотите реализовать это как макрос,

char *CStrNullLastNL_nl; // "private" global variable
#define nl ::CStrNullLastNL_nl // "locally" redeclare it
#define CStrNullLastNL( str ) ( \
    ( nl = strrchr( str, '\n') ), /* find newline if any */ \
    nl && ( *nl = 0 ), /* if found, null out */ \
    (char*) nl /* cast to rvalue and "return" */ \
OR  nl? str : NULL /* return input or NULL or whatever you like */
)
#undef nl // done with local usage
2 голосов
/ 21 апреля 2010

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

...