The most useful user-made C-macros (in GCC, also C

2020-05-11 09:51发布

What C macro is in your opinion is the most useful? I have found the following one, which I use to do vector arithmetic in 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];}

It works like that:

v3_op_v3(vectorA, +, vectorB, vectorC);
v3_op_v3(vectorE, *, vectorF, vectorJ);
...

18条回答
Root(大扎)
2楼-- · 2020-05-11 10:26

also multi-type Minimum and Maximum like that

//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; })
查看更多
趁早两清
3楼-- · 2020-05-11 10:27

If you need to define data multiple times in different contexts, macros can help you avoid have to relist the same thing multiple times.

For example, lets say you want to define an enum of colors and an enum-to-string function, rather then list all the colors twice, you could create a file of the colors (colors.def):

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

Now you can in your c file you can define your enum and your string conversion function:

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]);
};
查看更多
【Aperson】
4楼-- · 2020-05-11 10:28

The key point with C macros is to use them properly. In my mind there are three categories (not considering using them just to give descriptive names to constants)

  1. As a shorthand for piece of codes one doesn't want to repeat
  2. Provide a general use function
  3. Modify the structure of the C language (apparently)

In the first case, your macro will live just within your program (usually just a file) so you can use macros like the one you have posted that is not protected against double evaluation of parameters and uses {...}; (potentially dangerous!).

In the second case (and even more in the third) you need to be extremely careful that your macros behave correctly as if they were real C constructs.

The macro you posted from GCC (min and max) is an example of this, they use the global variables _a and _b to avoid the risk of double evaluation (like in max(x++,y++)) (well, they use GCC extensions but the concept is the same).

I like using macros where it helps to make things more clear but they are a sharp tool! Probably that's what gave them such a bad reputation, I think they are a very useful tool and C would have been much poorer if they were not present.

I see others have provided examples of point 2 (macros as functions), let me give an example of creating a new C construct: the Finite state machine. (I've already posted this on SO but I can't seem to be able to find it)

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

that you use this way:

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

You can add variation on this theme to get the flavour of FSM you need.

Someone may not like this example but I find it perfect to demonstrate how simple macros can make your code more legible and expressive.

查看更多
三岁会撩人
5楼-- · 2020-05-11 10:28

I also like this one:

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

And how you macros-haters do fair floating-point comparisons?

查看更多
乱世女痞
6楼-- · 2020-05-11 10:30
#define kroundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x))

Find the closest 32bit unsigned integer that is larger than x. I use this to double the size of arrays (i.e. the high-water mark).

查看更多
我欲成王,谁敢阻挡
7楼-- · 2020-05-11 10:32

for-each loop in 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);
}
查看更多
登录 后发表回答