4

I have been looking for interesting and preferably useful C macro/defines examples that wold be a bit more extensive than defining consts or min/max functions. It is my understanding that macros should allow some level of metaprogramning (though I'm not exactly sure), but searching fails to reveal much, so examples of metaprograming with macros would be very appreciated, or explanation why it can't work. Overall I'm interested in any "cool" macro uses.

P.S. I understand that question can get "not constructive & close" quickly, but I think it could at least become interesting community wiki question.

EDIT: I'm not interested in anything C++, anything.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
morphles
  • 2,424
  • 1
  • 24
  • 26
  • http://www.boost.org/doc/libs/1_51_0/libs/preprocessor/doc/index.html – Mat Oct 21 '12 at 09:00
  • This question may better be rephrased as, "what is the proper use of macros besides defining consts or min/max functions?" Or maybe even, "when should I use a macro instead of a simple function? What's the advantage?" – cegfault Oct 21 '12 at 09:04
  • There are some thing macros are simply *required* for. The most immediate example is anything that requires line-level source-file-location of code. ____FILE____ and ____LINE____ and their use via macro-expansion in tracing code execution progress is a *god-send*. – WhozCraig Oct 21 '12 at 09:09
  • 1
    You might be interested by the [P99 - Preprocessor macros and functions for C99](http://p99.gforge.inria.fr/) project. – deltheil Oct 21 '12 at 09:44
  • Thanks deltheil this seems very interesting. – morphles Oct 21 '12 at 09:52
  • Although you're not interested in C++, I'd still recommend to take a look at LLVM and Clang, they're using preprocessor in quite a creative manner (and you can use all the same tricks with plain C). See all the `.def` files there and find the places where they're included. – SK-logic Oct 25 '12 at 07:29
  • related: http://stackoverflow.com/questions/13459300/c-preprocessor-pseudo-assembly-with-embedded-byte-code-interpreter-how-to-find . Also see: http://stackoverflow.com/questions/6635851/real-world-use-of-x-macros . – luser droog Dec 20 '12 at 22:37

2 Answers2

6

Inspired by this question, the other day I was experimenting with other "inventive" uses of macros and here's what I've come up with so far, a set of macros to ensure that their parameters are of certain "type". These can be used as part of other macros:

#include <stdio.h>

// Only pointers can be dereferenced.
// This fails to compile if x is
// numeric type (or void*).
#define ACCEPT_PTR(x) \
  ((x) + sizeof(*(x)) * 0)

// sizeof() is evaulated at compile time and
// it will fail if the expression is non-const
// at compile time.
// (void*)&array == (void*)&array[0] is a
// compile-time const.
// (void*)&ptr == (void*)&ptr[0] needs the value of
// ptr and therefore isn't a compile-time const,
// same with (void*)&int == (void*)int.
#define ACCEPT_ARR(x) \
  ((x) + sizeof(struct { int not_an_array: ((void*)&(x) == &(x)[0]); }) * 0)
//  ((x) + sizeof(char[(void*)&(x) == (void*)&(x)[0]]) * 0)

// x can be added to itself or multiplied only
// if it's a numerical type, pointers can't be added.
#define ACCEPT_NUM(x) \
  ((x) * 1)
//  (((x) + (x)) - (x))

// Only integers can be shifted
// (% also applies to integers only).
// This will fail to compile if x isn't integer.
#define ACCEPT_INT(x) \
  ((x) << 0)
//  ((x) + (x) % 2 * 0)

// x will be concatenated with "" at compile
// time only if it's a string literal. Comilation
// will fail if x isn't a string literal.
#define ACCEPT_STR(x) \
  x ""

#define ACCEPT_LVAL(x) \
  (*&(x))

int main(void)
{
  int i = 42;
  int* p = &i;
  int a[1] = { 42 };
  float f = 42.0;

  ACCEPT_NUM(i);
  ACCEPT_NUM(p[0]);
  ACCEPT_NUM(a[0]);
//  ACCEPT_NUM(p);
//  ACCEPT_NUM(a);
//  ACCEPT_NUM("42");

  ACCEPT_INT(i);
  ACCEPT_INT(p[0]);
  ACCEPT_INT(a[0]);
  ACCEPT_INT("a"[0]);
//  ACCEPT_INT(p);
//  ACCEPT_INT(a);
//  ACCEPT_INT("42");
//  ACCEPT_INT(f);

  ACCEPT_PTR(&i);
  ACCEPT_PTR(p);
  ACCEPT_PTR(a);
  ACCEPT_PTR(&a[0]);
  ACCEPT_PTR("42");
  ACCEPT_PTR(&"a"[0]);
//  ACCEPT_PTR(i);
//  ACCEPT_PTR(f);

//  ACCEPT_ARR(a); // doesn't compile with OW :(
//  ACCEPT_ARR(i);
//  ACCEPT_ARR(p);
//  ACCEPT_ARR("42"); // WTF?; compiles with gcc :(
//  ACCEPT_ARR(f);

  ACCEPT_STR("42");
//  ACCEPT_STR(i);
//  ACCEPT_STR(p);
//  ACCEPT_STR(a);
//  ACCEPT_STR(f);

  ACCEPT_LVAL(i);
  ACCEPT_LVAL(p);
  ACCEPT_LVAL(p[0]);
  ACCEPT_LVAL(a); // not exactly lval
  ACCEPT_LVAL(a[0]);
//  ACCEPT_LVAL("42"); // WTF?; compiles with gcc but not with OW :(
  ACCEPT_LVAL(f);
//  ACCEPT_LVAL(0);
//  ACCEPT_LVAL(0.0);
//  ACCEPT_LVAL('a');

  return 0;
}
Community
  • 1
  • 1
Alexey Frunze
  • 61,140
  • 12
  • 83
  • 180
1

Search around for old versions of generic.h if you wanna see abuse of the preprocessor.

It was basically template style collections before templates.

JimR
  • 15,513
  • 2
  • 20
  • 26