web-dev-qa-db-fra.com

Demandez à la macro de «renvoyer» une valeur

J'utilise une macro et je pense que cela fonctionne bien -

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

Donc, cela fonctionne pour mettre à zéro le dernier saut de ligne dans une chaîne, vraiment son utilisé pour couper le saut de ligne quand il est laissé par les fgets.

Donc, je me demande si je peux "retourner" une valeur de la macro, donc on peut l'appeler comme

 func (CStrNullLastNL (cstr)); 

Ou devrais-je écrire une fonction

22
bobobobo

Pour qu'une macro "renvoie une valeur", la macro elle-même doit être une expression. Votre macro est un bloc d'instructions, qui ne peut pas être évalué en une expression.

Vous devez vraiment écrire une fonction inline. Il sera tout aussi rapide et beaucoup plus facile à maintenir.

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

devrait marcher.

Edit: ... dans GCC.

27
Danvil

Les macros ne renvoient pas de valeurs. Les macros indiquent au préprocesseur de remplacer tout ce qui se trouve après le #define avec tout ce qui est après la chose après le #define. Le résultat doit être un C++ valide.

Ce que vous demandez, c'est comment rendre les éléments suivants valides:

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

Je ne peux pas penser à un bon moyen de transformer cela en quelque chose de valide, autre que d'en faire un véritable appel de fonction. Dans ce cas, je ne sais pas pourquoi une macro serait meilleure qu'une fonction en ligne. C'est ce que vous demandez vraiment.

6
i_am_jorf

Si vous voulez vraiment le faire, obtenez un compilateur qui prend en charge les lambdas de style C++ 0x:

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

Bien que CStrNullLastNL soit fondamentalement une fonction, vous devriez probablement la réécrire en tant que fonction.

5
MSN

Pouvez-vous utiliser l'opérateur virgule? Exemple simplifié:

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

Ici B = SomeMacro (A) "renvoie" le résultat de Permute (A) et l'assigne à "B".

5
Adisak

Si vous n'avez pas l'obligation stricte d'utiliser uniquement des macros, vous pouvez faire quelque chose comme ça (exemple réel):

#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;
}

Et puis utilisez-le dans votre code comme ceci:

auto event = Q_XCB_SEND_EVENT_ALIGNED(xcb_unmap_notify_event_t);
4
gatis paeglis

J'ai donné +1 à Mike parce qu'il a 100% raison, mais si vous voulez implémenter cela en tant que macro,

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
4
Potatoswatter

Le retour d'une valeur est à quoi servent les fonctions en ligne. Et assez souvent, lesdites fonctions en ligne sont mieux adaptées aux tâches que les macros, qui sont très dangereuses et n'ont aucun type en toute sécurité.

3
Michael Dorgan