代码之家  ›  专栏  ›  技术社区  ›  psihodelia

最有用的用户自定义C宏(在GCC中,也是C99)[关闭]

  •  27
  • psihodelia  · 技术社区  · 15 年前

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

    v3_op_v3(vectorA, +, vectorB, vectorC);
    v3_op_v3(vectorE, *, vectorF, vectorJ);
    ...
    
    18 回复  |  直到 9 年前
        1
  •  18
  •   Johannes Schaub - litb    10 年前

    对于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);
    }
    
        2
  •  37
  •   AnT stands with Russia    15 年前
    #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)
    

    当然,还有各种各样的最小值、最大值、ABS等。

    IMPLIES 宏作为最有用的宏之一。它的主要目的是便于编写更优雅、可读性更强的断言,如

    void foo(int array[], int n) {
      assert(IMPLIES(n > 0, array != NULL));
      ...
    
        3
  •  24
  •   Remo.D    15 年前

    1. 作为一段代码的简写,人们不想重复

    在第一种情况下,您的宏将位于您的程序中(通常只是一个文件),因此您可以使用与您发布的宏类似的宏,该宏不受参数和使用的双重计算的保护 {...};

    在第二种情况下(第三种情况下甚至更多),你需要

    您从GCC发布的宏(min和max)就是一个例子,它们使用全局变量 _a _b 避免双重评估的风险(如 max(x++,y++) )(他们使用GCC扩展,但概念是一样的)。

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

    您使用这种方式:

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

    你可以在这个主题上添加变化,以获得你所需要的FSM的味道。

        4
  •  11
  •   srparish    15 年前

    如果需要在不同的上下文中多次定义数据,宏可以帮助您避免多次重新列出相同的内容。

    colors.def ):

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

    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]);
    };
    
        5
  •  7
  •   Clifford    15 年前
    #if defined NDEBUG
        #define TRACE( format, ... )
    #else
        #define TRACE( format, ... )   printf( "%s::%s(%d)" format, __FILE__, __FUNCTION__,  __LINE__, __VA_ARGS__ )
    #endif
    

    请注意,之间缺少逗号 "%s::%s(%d)" format 这是故意的。它打印一个带有源位置前缀的格式化字符串。我在实时嵌入式系统中工作,所以经常在输出中包含时间戳。

        6
  •  6
  •   Joe D    15 年前

    用于GCC的Foreach循环,特别是带有GNU扩展的C99。使用字符串和数组。可以通过将动态分配的数组强制转换为指向数组的指针,然后取消对它们的引用来使用它们。

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

    这段代码已经过测试,可以在GNU/Linux上与GCC、ICC和Clang一起使用。

    Lambda表达式(仅限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);
    }
    
        7
  •  6
  •   Community CDub    8 年前

    有人提到 container_of()

    struct thing {
        int a;
        int b;
    };
    

    现在如果我们有一个指向 B ,我们可以使用 (的)容器 事情

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

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

    这不是疯狂的宏代码。它将提供关于错误的良好编译器行号,并与调试器配合使用。它也是相当类型安全的,除了结构使用多种类型的情况(例如,如果我们允许的话) 颜色 一)。

    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);
    
        8
  •  5
  •   EvilTeach    15 年前
    #define COLUMNS(S,E) [ (E) - (S) + 1 ]
    
    
    struct 
    {
        char firstName COLUMNS ( 1, 20);
        char LastName  COLUMNS (21, 40);
        char ssn       COLUMNS (41, 49);
    }
    

    节省一些容易出错的计数

        9
  •  4
  •   Alexandru    15 年前

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

    其他答案中缺少另一个:

    #define LSB(x) ((x) ^ ((x) - 1) & (x))   // least significant bit
    
        10
  •  2
  •   psihodelia    15 年前

    我也喜欢这个:

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

        11
  •  2
  •   outis    15 年前

    只有标准的:

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

    但是那里没有什么太漂亮的东西。

        12
  •  2
  •   user172818    15 年前
    #define kroundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x))
    

    查找最接近的大于x的32位无符号整数。我使用它将数组的大小增加一倍(即高水位线)。

        13
  •  1
  •   Hernán    15 年前

    将字节、字、DWORD打包为字、DWORD和QWORD:

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

    插入参数避免扩展的副作用始终是一种好的做法。

        14
  •  0
  •   psihodelia    15 年前

    还有多类型的最小值和最大值

    //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; })
    
        15
  •  0
  •   psihodelia    15 年前

    检查是否使用浮点 x

    #define ISNAN(x) ((x) != (x))
    
        16
  •  0
  •   justin    15 年前

    我经常使用的一个(极少数)宏是将参数或变量声明为未使用的宏。要注意这一点,最兼容的解决方案(IMHO)因编译器而异。

        17
  •  -1
  •   psihodelia    15 年前

    这一个太棒了:

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

    我使用它就像:

    object = NEW(object_type, 1);
    
        18
  •  -1
  •   T.E.D.    15 年前

    真与假似乎很受欢迎。