Pergunta

O que C macro está em sua opinião, é mais útil?Eu encontrei a seguinte, o que eu uso para fazer aritmética vetorial em 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 assim:

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

Solução

FOR-EAGE LOOP EM 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);
}

Outras dicas

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

E, claro, vários min, máximo, abdominais etc.

Observe, btw, que nenhuma das opções acima pode ser implementada por uma função em C.

PS eu provavelmente iria destacar o acima IMPLIES macro como um dos mais úteis. Seu principal objetivo é facilitar a escrita de afirmações mais elegantes e legíveis, como em

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

O ponto-chave com C macros é usá-las corretamente.Em minha mente, há três categorias (não considerando utilizando-os apenas para dar nomes descritivos constantes)

  1. Como um atalho para o pedaço de códigos de um não quer repetir
  2. De uma forma geral, use a função
  3. Modificar a estrutura da linguagem C (aparentemente)

No primeiro caso, a macro irá viver apenas dentro de seu programa (normalmente apenas um arquivo), então você pode usar macros, como o que você postou não é protegido contra a dupla avaliação de parâmetros e usa {...}; (potencialmente perigoso!).

No segundo caso (e ainda mais no terceiro) você precisa ser extremamente cuidado para que suas macros se comportar como se fossem reais C construções.

A macro que você postou do GCC (min e max) é um exemplo disso, eles usam variáveis globais _a e _b para evitar o risco de duplo avaliação (como em max(x++,y++)) (bem, eles usam extensões GCC, mas o conceito é o mesmo).

Eu gosto de usar macros, onde ele ajuda a tornar as coisas mais claro, mas eles são uma ferramenta afiada!Provavelmente é o que lhes deu uma reputação tão ruim, eu acho que eles são uma ferramenta muito útil e C teria sido muito pior se eles não estavam presentes.

Eu vejo os outros têm exemplos fornecidos do ponto 2 (macros, funções), deixe-me dar um exemplo de criação de um novo C a construir:a máquina de estado Finito.(Eu já postei isso sobre ISSO, mas eu não consigo ser capaz de encontrá-lo)

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

que você use esta forma:

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

Você pode adicionar variação sobre esse tema, para obter o sabor do FSM que você precisa.

Alguém pode não gostar desse exemplo, mas acho que é perfeita para demonstrar como macros simples pode tornar seu código mais legível e expressiva.

Se você precisar definir dados várias vezes em diferentes contextos, as macros podem ajudar a evitar que precise relatar a mesma coisa várias vezes.

Por exemplo, digamos que você queira definir uma enumeração de cores e uma função enum para cordão, em vez de listar todas as cores duas vezes, você pode criar um arquivo das cores (colors.def):

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

Agora você pode no seu arquivo C, você pode definir sua enumeração e sua função de conversão de string:

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

Observe que a falta de vírgula entre "%s::%s(%d)" e format é deliberado. Ele imprime uma corda formatada com o local da fonte preso. Trabalho em sistemas incorporados em tempo real, com frequência, também incluo um registro de data e hora na saída.

Foreach loop para GCC, especificamente C99 com extensões GNU. Trabalha com cordas e matrizes. Matrizes alocadas dinamicamente podem ser usadas, lançando -as para um ponteiro para uma matriz e depois desreferendo -as.

#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 foi testado para trabalhar com GCC, ICC e CLANG no GNU/Linux.

Expressões Lambda (somente GCC)

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

Economize -se algum erro propenso a contagem

Alguém mencionou container_of (), mas não forneceu uma explicação para essa macro realmente útil. Digamos que você tenha uma estrutura que se pareça com a seguinte:

struct thing {
    int a;
    int b;
};

Agora, se tivermos um ponteiro para b, podemos usar container_of () Para conseguir um ponteiro para coisa de maneira segura de tipo:

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

Isso é útil na criação de estruturas de dados abstratas. Por exemplo, em vez de adotar a fila de abordagem.

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

Que não é um código macro louco. Ele dará bons numbers de linha do compilador sobre erros e funcionará bem com o depurador. Também é razoavelmente tipos, exceto nos casos em que as estruturas usam vários tipos (por exemplo, se permitimos estrutura de estrutura no exemplo abaixo para estar em listas mais vinculadas do que apenas o cores 1).

Os usuários agora podem usar sua biblioteca como esta:

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

Este é do kernel Linux (específico do GCC):

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

Outro faltando de outras respostas:

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

Eu também gosto deste:

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

E como vocês-óculos de macros fazem comparações justas de ponto flutuante?

Apenas os padrão:

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

Mas não há nada demais lá.

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

Encontre o número inteiro não assinado de 32 bits mais próximo que é maior que x. Eu uso isso para dobrar o tamanho das matrizes (ou seja, a marca de água alta).

Pacote bytes, palavras, dwords em palavras, ddords e 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) 

Argumentos entre parênteses, é sempre uma boa prática evitar efeitos colaterais na expansão.

também o mínimo e o máximo de vários tipos como esse

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

Verificando se um ponto flutuante x não é um número:

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

Um (dos poucos) que eu uso regularmente é uma macro para declarar um argumento ou variável como não utilizada. A solução mais compatível para observar isso (IMHO) varia de acordo com o compilador.

Este é incrível:

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

E eu uso como:

object = NEW(object_type, 1);

Verdadeiro e falso parecem ser populares.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top