Pregunta

¿ C macro es en su opinión es la más útil?He encontrado la siguiente, la que yo uso para hacer aritmética de vectores en 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];}

Funciona así:

v3_op_v3(vectorA, +, vectorB, vectorC);
v3_op_v3(vectorE, *, vectorF, vectorJ);
...
¿Fue útil?

Solución

para-cada bucle 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);
}

Otros consejos

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

Y, por supuesto, varios MIN, MAX, ABS, etc.

Nota, por cierto, que ninguno de los anteriores puede ser implementada por una función en C.

P.S. Yo probablemente destacar la macro IMPLIES anteriormente como uno de los más útiles. Su objetivo principal es facilitar la escritura de las afirmaciones más elegantes y legibles, como en

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

El punto clave de C macros es usarlos correctamente.En mi mente hay tres categorías (no considerando el uso de ellos sólo para dar nombres descriptivos a las constantes)

  1. Como una abreviación de la pieza de códigos no quieren repetir
  2. Proporcionar un uso general de la función
  3. Modificar la estructura de la lengua C (aparentemente)

En el primer caso, la macro se viven dentro de su programa (por lo general sólo un archivo) así que usted puede utilizar las macros como el que usted ha publicado que no está protegido en contra de la doble evaluación de parámetros y usos {...}; (potencialmente peligroso!).

En el segundo caso (y más aún en la tercera) que usted necesita para ser muy cuidado de que las macros se comportan correctamente como si fueran reales C construcciones.

La macro que has publicado de GCC (min y max) es un ejemplo de esto, que el uso de las variables globales _a y _b para evitar el riesgo de doble evaluación (como en max(x++,y++)) (bueno, usar GCC extensiones, pero el concepto es el mismo).

Me gusta el uso de macros donde ayuda a hacer las cosas más claras, pero son una herramienta afilada!Probablemente eso es lo que les dio una mala reputación, creo que son una herramienta muy útil y C habría sido mucho peor si no estaban presentes.

Veo a otros ejemplos del punto 2 (macros, funciones), permítanme darles un ejemplo de creación de un nuevo C construcción:la máquina de estados Finitos.(Ya he publicado esto en algo ASÍ, pero me parece que no puede ser capaz de encontrarlo)

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

que utilice esta manera:

 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 */
 } 

Usted puede agregar variación de este tema para obtener el sabor de la FSM que usted necesita.

A alguien no le guste este ejemplo, pero creo que es perfecto para demostrar cómo macros sencillas puede hacer el código más legible y expresivo.

Si necesita definir varias veces los datos en diferentes contextos, las macros pueden ayudar a evitar que tenga que poner en venta el mismo varias veces.

Por ejemplo, digamos que usted quiere definir una enumeración de los colores y una función de enumeración a cadena, en lugar de enumerar todos los colores en dos ocasiones, se puede crear un archivo de los colores ( colors.def ):

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

Ahora se puede en el archivo c puede definir su enumeración y su función de conversión de cadena:

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

Tenga en cuenta que la falta de una coma entre "%s::%s(%d)" y format es deliberado. Se imprime una cadena con formato de ubicación de origen antepuesto. Yo trabajo en sistemas embebidos en tiempo real tan a menudo también incluyo una marca de tiempo en la salida también.

bucle Foreach para GCC, específicamente C99 con extensiones de GNU. Funciona con cadenas y matrices. Dinámicamente arrays asignados se pueden utilizar por colada a un puntero a una matriz, y luego eliminación de referencias ellos.

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

Este código ha sido probado para trabajar con GCC, CPI y Sonido metálico en GNU / Linux.

Las expresiones lambda (GCC solamente)

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

Ahórrate el error de conteo propensos

Otra persona mencionó container_of () , pero no proporcionó una explicación para esta macro realmente útil. Digamos que tiene una estructura que se parece a esto:

struct thing {
    int a;
    int b;
};

Ahora bien, si tenemos un puntero a b , podemos usar container_of () para obtener un puntero a lo de una manera segura Tipo :

int *bp = ...;
struct thing *t = container_of(bp, struct thing, b);

Esto es útil en la creación de estructuras de datos abstractos. Por ejemplo, en lugar de tomar el enfoque queue.h toma para crear cosas como SLIST (toneladas de macros locos para cada operación), ahora se puede escribir una aplicación slist que se ve algo como esto:

struct slist_el {
    struct slist_el *next;
};

struct slist_head {
    struct slist_el *first;
};

void
slist_insert_head(struct slist_head *head, struct slist_el *el)
{
    el->next = head->first;
    head->first = el;
}

struct slist_el
slist_pop_head(struct slist_head *head)
{
    struct slist_el *el;

    if (head->first == NULL)
        return NULL;

    el = head->first;
    head->first = el->next;
    return (el);   
}

Lo que no es código de macro loco. Dará buen compilador números de línea en errores y funciona bien con el depurador. Es también bastante typesafe, a excepción de los casos en estructuras utilizan varios tipos (por ejemplo, si permitimos Color del struct en el ejemplo siguiente para estar en las listas de más vinculados que sólo los colores una) .

Ahora los usuarios pueden utilizar la biblioteca de la siguiente manera:

struct colors {
    int r;
    int g;
    int b;
    struct slist_el colors;
};

struct *color = malloc(sizeof(struct person));
color->r = 255;
color->g = 0;
color->b = 0;
slist_insert_head(color_stack, &color->colors);
...
el = slist_pop_head(color_stack);
color = el == NULL ? NULL : container_of(el, struct color, colors);

Éste es de núcleo de Linux (gcc específico):

#define container_of(ptr, type, member) ({                  \
const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
    (type *)( (char *)__mptr - offsetof(type,member) ); })

Otra falta de otras respuestas:

#define LSB(x) ((x) ^ ((x) - 1) & (x))   // least significant bit

También como éste:

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

Y cómo macros que odian hacer comparaciones justa de punto flotante?

A sólo las normales:

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

pero no hay nada demasiado spiffy allí.

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

Encuentra el más cercano entero sin signo de 32 bits que es mayor que x. Lo utilizo para duplicar el tamaño de las matrices (es decir, la marca de agua alta).

Paquete bytes, palabras, dwords en palabras, y dwords 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) 

Los argumentos Parenthesizing que siempre es una buena práctica para evitar efectos secundarios en expansión.

también multi-tipo mínimo y máximo de esa manera

//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; })

Comprobación de si un punto flotante x no es un número:

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

Uno (de los muy pocos) que utilizo regularmente es una macro para declarar un argumento o variable como no utilizados. La solución más compatible a nota de este (mi humilde opinión) varía según el compilador.

Éste es impresionante:

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

Y lo uso como:

object = NEW(object_type, 1);

VERDADERO y FALSO parecen ser popular.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top