最有用的用户自制C-宏(在GCC中,也是C99)?

时间:2009-11-20 17:38:41

标签: c macros c-preprocessor c99

您认为 C 宏最有用吗?我找到了以下一个,用于在 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 个答案:

答案 0 :(得分:34)

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

当然还有各种MIN,MAX,ABS等。

请注意,顺便说一句,上述任何一项都不能用C中的函数实现。

P.S。我可能会将上面的IMPLIES宏作为最有用的宏之一。其主要目的是促进编写更优雅和可读的断言,如

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

答案 1 :(得分:21)

C宏的关键是正确使用它们。在我看来,有三个类别(不考虑使用它们只是为常量提供描述性名称)

  1. 作为一段代码的简写,我不想重复
  2. 提供一般使用功能
  3. 修改C语言的结构(显然)
  4. 在第一种情况下,您的宏将只存在于您的程序中(通常只是一个文件),因此您可以使用已发布的宏,这些宏不受保护,不会对参数进行双重评估,并使用{...};(有潜在危险!)。

    在第二种情况下(甚至更多在第三种情况下)你需要非常小心你的宏行为正确,好像它们是真正的C结构一样。

    您从GCC发布的宏(最小值和最大值)就是一个例子,他们使用全局变量_a_b来避免双重评估的风险(如max(x++,y++) (),他们使用GCC扩展,但概念是相同的。)

    我喜欢使用宏,它有助于使事情更清晰,但它们是一个敏锐的工具!可能这就是给他们带来如此糟糕声誉的东西,我认为他们是一个非常有用的工具,如果他们不在场,C会更差。

    我看到其他人提供了第2点的例子(宏作为函数),让我举一个创建新C结构的例子:有限状态机。 (我已经在SO上发布了这个,但我似乎无法找到它)

     #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风格。

    有人可能不喜欢这个例子,但我发现它非常适合演示简单的宏如何使你的代码更易读和更具表现力。

答案 2 :(得分:13)

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

答案 3 :(得分:10)

答案 4 :(得分:7)

答案 5 :(得分:6)

答案 6 :(得分:5)

答案 7 :(得分:5)

#define COLUMNS(S,E) [ (E) - (S) + 1 ]


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

为自己节省一些容易出错的计数

答案 8 :(得分:4)

这个是来自linux内核(具体是gcc):

#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

答案 9 :(得分:2)

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

找到最接近的大于x的32位无符号整数。我用这个来加倍阵列的大小(即高水位线)。

答案 10 :(得分:2)

只是标准的:

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

但那里没什么太漂亮的。

答案 11 :(得分:2)

我也喜欢这个:

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

你们如何对宏观者进行公平的浮点比较?

答案 12 :(得分:1)

将字节,单词,双字打包成单词,双字和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) 

使用括号参数,避免对扩展产生副作用始终是一种好习惯。

答案 13 :(得分:0)

也是多种类型的最小值和最大值

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

答案 14 :(得分:0)

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

答案 15 :(得分:0)

检查浮点 x 是否不是数字:

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

答案 16 :(得分:-1)

TRUE和FALSE似乎很受欢迎。

答案 17 :(得分:-1)

这个很棒:

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

我用它像:

object = NEW(object_type, 1);