Question

Qu'est-ce que C macro est à votre avis est le plus utile? J'ai trouvé la suivante, que j'utilise pour faire de l'arithmétique vectorielle dans C :

#define v3_op_v3(x, op, y, z) {z[0]=x[0] op y[0]; \
                               z[1]=x[1] op y[1]; \
                               z[2]=x[2] op y[2];}

Il fonctionne comme ça:

v3_op_v3(vectorA, +, vectorB, vectorC);
v3_op_v3(vectorE, *, vectorF, vectorJ);
...
Était-ce utile?

La solution

pour-chaque boucle en C99:

#define foreach(item, array) \
    for(int keep=1, \
            count=0,\
            size=sizeof (array)/sizeof *(array); \
        keep && count != size; \
        keep = !keep, count++) \
      for(item = (array)+count; keep; keep = !keep)

int main() {
  int a[] = { 1, 2, 3 };
  int sum = 0;
  foreach(int const* c, a)
    sum += *c;
  printf("sum = %d\n", sum);

  // multi-dim array
  int a1[][2] = { { 1, 2 }, { 3, 4 } };
  foreach(int (*c1)[2], a1)
    foreach(int *c2, *c1) 
      printf("c2 = %d\n", *c2);
}

Autres conseils

#define IMPLIES(x, y) (!(x) || (y))

#define COMPARE(x, y) (((x) > (y)) - ((x) < (y)))
#define SIGN(x) COMPARE(x, 0)

#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*a))

#define SWAP(x, y, T) do { T tmp = (x); (x) = (y); (y) = tmp; } while(0)
#define SORT2(a, b, T) do { if ((a) > (b)) SWAP((a), (b), T); } while (0)

#define SET(d, n, v) do{ size_t i_, n_; for (n_ = (n), i_ = 0; n_ > 0; --n_, ++i_) (d)[i_] = (v); } while(0)
#define ZERO(d, n) SET(d, n, 0)

Et, bien sûr, divers MIN, MAX, ABS etc.

Note, BTW, qu'aucun des ci-dessus peut être mis en œuvre par une fonction C.

P.S. Je serais probablement singulariser la macro IMPLIES ci-dessus comme l'un des plus utiles. Son but principal est de faciliter l'écriture des affirmations plus élégantes et lisibles, comme dans

void foo(int array[], int n) {
  assert(IMPLIES(n > 0, array != NULL));
  ...

Le point clé avec des macros C est de les utiliser correctement. Dans mon esprit, il y a trois catégories (ne pas considérer les utiliser juste pour donner des noms descriptifs à des constantes)

  1. En tant que raccourci pour morceau de code on ne veut pas répéter
  2. Fournir une fonction d'usage général
  3. Modifier la structure du langage C (apparemment)

Dans le premier cas, votre macro va vivre juste dans votre programme (généralement juste un fichier) de sorte que vous pouvez utiliser des macros comme celui que vous avez posté non protégé contre la double évaluation des paramètres et utilise {...}; (potentiellement dangereux!) .

Dans le second cas (et plus encore dans le troisième) vous devez être très Veillez à ce que vos macros se comportent correctement comme si elles étaient des constructions réelles C.

La macro que vous avez publié de GCC (min et max) est un exemple de cela, ils utilisent les variables globales _a et _b pour éviter le risque de double évaluation (comme dans max(x++,y++)) (bien, ils utilisent des extensions du CCG, mais le concept est le même).

J'aime utiliser des macros où il aide à rendre les choses plus claires, mais elles sont un outil pointu! Probablement c'est ce qui leur a donné une si mauvaise réputation, je pense qu'ils sont un outil très utile et C auraient été beaucoup moins bonne si elles ne sont pas présents.

Je vois d'autres ont fourni des exemples de point 2 (macros comme fonctions), permettez-moi de donner un exemple de la création d'une nouvelle construction C: la machine à états finis. (Je l'ai déjà posté sur le SO, mais je ne peux pas l'air d'être capable de le trouver)

 #define FSM            for(;;)
 #define STATE(x)       x##_s 
 #define NEXTSTATE(x)   goto x##_s

que vous utilisez cette façon:

 FSM {
    STATE(s1):
      ... do stuff ...
      NEXTSTATE(s2);

    STATE(s2):
      ... do stuff ...
      if (k<0) NEXTSTATE(s2); 
      /* fallthrough as the switch() cases */

    STATE(s3):
      ... final stuff ...
      break;  /* Exit from the FSM */
 } 

Vous pouvez ajouter une variation sur ce thème pour obtenir la saveur des États fédérés de Micronésie dont vous avez besoin.

Quelqu'un peut ne pas aimer cet exemple, mais je le trouve parfait pour démontrer comment de simples macros peuvent rendre votre code plus lisible et expressif.

Si vous devez définir les temps de multiples données dans des contextes différents, les macros peuvent vous aider à éviter doivent remettre en vente la même chose plusieurs fois.

Par exemple, disons que vous voulez définir un ENUM de couleurs et une fonction ENUM à chaîne, plutôt la liste ensuite toutes les couleurs deux fois, vous pouvez créer un fichier des couleurs ( colors.def ):

c(red)
c(blue)
c(green)
c(yellow)
c(brown)

Maintenant, vous pouvez dans votre fichier c vous pouvez définir votre ENUM et votre fonction de conversion de chaîne:

enum {
#define c(color) color,
# include "colors.def"
#undef c
};

const char *
color_to_string(enum color col)
{
    static const char *colors[] = {
#define c(color) #color,
# include "colors.def"
#undef c
    };
    return (colors[col]);
};
#if defined NDEBUG
    #define TRACE( format, ... )
#else
    #define TRACE( format, ... )   printf( "%s::%s(%d)" format, __FILE__, __FUNCTION__,  __LINE__, __VA_ARGS__ )
#endif

Notez que l'absence d'une virgule entre "%s::%s(%d)" et format est délibérée. Il imprime une chaîne formatée avec emplacement source Prepended. Je travaille en temps réel des systèmes embarqués si souvent j'inclure également un horodatage dans la sortie ainsi.

boucle foreach pour GCC, en particulier C99 avec les extensions GNU. Fonctionne avec des chaînes et des tableaux. Dynamiquement tableaux alloués peuvent être utilisés en les jetant à un pointeur vers un tableau, puis les déréférencement.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

#define FOREACH_COMP(INDEX, ARRAY, ARRAY_TYPE, SIZE) \
  __extension__ \
  ({ \
    bool ret = 0; \
    if (__builtin_types_compatible_p (const char*, ARRAY_TYPE)) \
      ret = INDEX < strlen ((const char*)ARRAY); \
    else \
      ret = INDEX < SIZE; \
    ret; \
  })

#define FOREACH_ELEM(INDEX, ARRAY, TYPE) \
  __extension__ \
  ({ \
    TYPE *tmp_array_ = ARRAY; \
    &tmp_array_[INDEX]; \
  })

#define FOREACH(VAR, ARRAY) \
for (void *array_ = (void*)(ARRAY); array_; array_ = 0) \
for (size_t i_ = 0; i_ && array_ && FOREACH_COMP (i_, array_, \
                                    __typeof__ (ARRAY), \
                                    sizeof (ARRAY) / sizeof ((ARRAY)[0])); \
                                    i_++) \
for (bool b_ = 1; b_; (b_) ? array_ = 0 : 0, b_ = 0) \
for (VAR = FOREACH_ELEM (i_, array_, __typeof__ ((ARRAY)[0])); b_; b_ = 0)

/* example's */
int
main (int argc, char **argv)
{
  int array[10];
  /* initialize the array */
  int i = 0;
  FOREACH (int *x, array)
    {
      *x = i;
      ++i;
    }

  char *str = "hello, world!";
  FOREACH (char *c, str)
    printf ("%c\n", *c);

  /* Use a cast for dynamically allocated arrays */
  int *dynamic = malloc (sizeof (int) * 10);
  for (int i = 0; i < 10; i++)
    dynamic[i] = i;

  FOREACH (int *i, *(int(*)[10])(dynamic))
    printf ("%d\n", *i);

  return EXIT_SUCCESS;
}

Ce code a été testé pour fonctionner avec GCC, ICC et Clang sur GNU / Linux.

expressions Lambda (GCC uniquement)

#define lambda(return_type, ...) \
  __extension__ \
  ({ \
    return_type __fn__ __VA_ARGS__ \
    __fn__; \
  })

int
main (int argc, char **argv)
{
  int (*max) (int, int) = 
    lambda (int, (int x, int y) { return x > y ? x : y; });
  return max (1, 2);
}
#define COLUMNS(S,E) [ (E) - (S) + 1 ]


struct 
{
    char firstName COLUMNS ( 1, 20);
    char LastName  COLUMNS (21, 40);
    char ssn       COLUMNS (41, 49);
}

Epargnez-vous une erreur de comptage sujette

Je aime aussi celui-ci:

#define COMPARE_FLOATS(a,b,epsilon) (fabs(a - b) <= epsilon * fabs(a))

Et comment vous macros-haters faire des comparaisons à virgule flottante juste?

Juste les standards:

#define LENGTH(array) (sizeof(array) / sizeof (array[0]))
#define QUOTE(name) #name
#define STR(name) QUOTE(name)

mais il n'y a rien de trop épatant là.

#define kroundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x))

Trouver le plus proche 32bit entier non signé qui est plus grand que x. J'utilise ceci pour doubler la taille des réseaux (à savoir la ligne des hautes eaux).

octets Pack, mots, doubles mots en mots, dwords et qwords:

#define ULONGLONG unsigned __int64
#define MAKEWORD(h,l) ((unsigned short) ((h) << 8)) | (l)
#define MAKEDWORD(h,l) ((DWORD) ((h) << 16)) | (l)
#define MAKEQWORD(h,l) ((ULONGLONG)((h) << 32)) | (l) 

arguments de parenthésage il est toujours une bonne pratique pour éviter les effets secondaires sur l'expansion.

également minimum et maximum comme multi-type

//NOTE: GCC extension !
#define max(a,b) ({typeof (a) _a=(a); typeof (b) _b=(b); _a > _b ? _a:_b; })
#define min(a,b) ({typeof (a) _a=(a); typeof (b) _b=(b); _a < _b ? _a:_b; })

Vérifier si un virgule flottante x est pas un nombre:

#define ISNAN(x) ((x) != (x))

L'un (des très rares) que j'utilise est régulièrement une macro pour déclarer un argument ou variable utilisé. La solution la plus compatible de noter ce (à mon humble avis) varie par le compilateur.

Celui-ci est impressionnant:

#define NEW(type, n) ( (type *) malloc(1 + (n) * sizeof(type)) )

Je l'utilise comme:

object = NEW(object_type, 1);

VRAI et FAUX semblent être populaire.

scroll top