As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 10 years ago.
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);
...
#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)
And, of course, various MIN, MAX, ABS etc.
Note, BTW, that none of the above can be implemented by a function in C.
P.S. I would probably single out the above IMPLIES macro as one of the most useful ones. Its main purpose is to facilitate writing of more elegant and readable assertions, as in
void foo(int array[], int n) {
assert(IMPLIES(n > 0, array != NULL));
...
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)
As a shorthand for piece of codes one doesn't want to repeat
Provide a general use function
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.
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);
}
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]);
};
#if defined NDEBUG
#define TRACE( format, ... )
#else
#define TRACE( format, ... ) printf( "%s::%s(%d)" format, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__ )
#endif
Note that the lack of a comma between "%s::%s(%d)" and format is deliberate. It prints a formatted string with source location prepended. I work in real-time embedded systems so often I also include a timestamp in the output as well.
Foreach loop for GCC, specifically C99 with GNU Extensions. Works with strings and arrays. Dynamically allocated arrays can be used by casting them to a pointer to an array, and then dereferencing them.
#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;
}
This code has been tested to work with GCC, ICC and Clang on GNU/Linux.
Lambda expressions (GCC only)
#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);
}
Someone else mentioned container_of(), but didn't provide an explanation for this really handy macro. Let's say you have a struct that looks like this:
struct thing {
int a;
int b;
};
Now if we have a pointer to b, we can use container_of() to get a pointer to thing in a type safe fashion:
int *bp = ...;
struct thing *t = container_of(bp, struct thing, b);
This is useful in creating abstract data structures. For example, rather than taking the approach queue.h takes for creating things like SLIST (tons of crazy macros for every operation), you can now write an slist implementation that looks something like this:
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);
}
Which is not crazy macro code. It will give good compiler line-numbers on errors and works nice with the debugger. It's also fairly typesafe, except for cases where structs use multiple types (eg if we allowed struct color in the below example to be on more linked lists than just the colors one).
Users can now use your library like this:
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);
#define COLUMNS(S,E) [ (E) - (S) + 1 ]
struct
{
char firstName COLUMNS ( 1, 20);
char LastName COLUMNS (21, 40);
char ssn COLUMNS (41, 49);
}
Save yourself some error prone counting
This one is from linux kernel (gcc specific):
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) ); })
Another missing from other answers:
#define LSB(x) ((x) ^ ((x) - 1) & (x)) // least significant bit
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?
Just the standard ones:
#define LENGTH(array) (sizeof(array) / sizeof (array[0]))
#define QUOTE(name) #name
#define STR(name) QUOTE(name)
but there's nothing too spiffy there.
#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).
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; })
Pack bytes,words,dwords into words,dwords and 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)
Parenthesizing arguments it's always a good practice to avoid side-effects on expansion.
This one is awesome:
#define NEW(type, n) ( (type *) malloc(1 + (n) * sizeof(type)) )
And I use it like:
object = NEW(object_type, 1);
Checking whether a floating point x is Not A Number:
#define ISNAN(x) ((x) != (x))
One (of the very few) that I use regularly is a macro to declare an argument or variable as unused. The most compatible solution to note this (IMHO) varies by compiler.
TRUE and FALSE seem to be popular.
Related
I ran this code in this compiler
#define CCc(n) CC_##n
#define CC(n) CCc(n)
#define CC_1 (1,2)
#define CC_2 (3,4)
#define CALL_FUNCTION(xy) Coord(xy)
#define YES 1
#define NO 0
int Coord(x, y){
if (x < 0.5 && y < 1.5){
return YES;
}
return NO;
}
int main()
{
for(int i = 1; i < 3; i++){
CALL_FUNCTION(CC(i));
}
return 0;
}
and got this error:
error: use of undeclared identifier 'CC_i'
Why does this error occur? And what is the right way to achieve this?
You cannot do run-time/variable evaluations in the pre-processor. It requires compile-time pre-processor tokens. So rather than trying to define a number of #define based on run-time values, you should gather all compile-time constants in one place.
A common way to do so is "X macros". In your case it might look like this:
#define CC_LIST \
/* n x y */ \
X(1, 1, 2) \
X(2, 3, 4) \
int main()
{
#define X(n,x,y) (void) Coord(x, y);
CC_LIST
#undef X
return 0;
}
This expands to (void) Coord(1,2); (void) Coord(3,4);, so it is a compile-time loop unrolling of sorts.
Alternatively, if you insist on having the "CC_N" macros because they are also needed for other purposes, you can do this:
#define CC_LIST \
/* n */ \
X(1) \
X(2) \
#define CC(n) CC_##n
#define CC_1 1,2
#define CC_2 3,4
#define CALL_FUNCTION(...) (void) Coord(__VA_ARGS__);
int main()
{
#define X(n) CALL_FUNCTION(CC(n))
CC_LIST
#undef X
return 0;
}
As you can tell, macro tricks like "X macros" are not easy to read and should be regarded as the last resort. Only use them when proper program re-design is not possible, for example during maintenance of existing code.
I'm trying to work through an issue on a third party library. The issue is the library uses GCC's nested functions buried in a macro, and Clang does not support nested functions and has no plans to do so (cf., Clang Bug 6378 - error: illegal storage class on function).
Here's the macro that's the pain point for me and Clang:
#define RAII_VAR(vartype, varname, initval, dtor) \
/* Prototype needed due to http://gcc.gnu.org/bugzilla/show_bug.cgi?id=36774 */ \
auto void _dtor_ ## varname (vartype * v); \
void _dtor_ ## varname (vartype * v) { dtor(*v); } \
vartype varname __attribute__((cleanup(_dtor_ ## varname))) = (initval)
And here's how its used (from the code comments):
* void do_stuff(const char *name)
* {
* RAII_VAR(struct mything *, thing, find_mything(name), ao2_cleanup);
* if (!thing) {
* return;
* }
* if (error) {
* return;
* }
* do_stuff_with_thing(thing);
* }
The Clang User Manual states to use C++ and a lambda function to emulate. I'm not sure that's the best strategy, and a C project will likely not accept a C++ patch (they would probably tar and feather me first).
Is there a way to rewrite the macro so that's its (1) more accommodating to Clang, and (2) preserves original function semantics?
Clang doesn't support GCC nested functions, but it does support Objective C-style "blocks", even in C mode:
void f(void * d) {
void (^g)(void *) = ^(void * d){ };
g(d);
}
You need to invoke it with the clang command rather than gcc, and also (?) pass -fblocks -lBlocksRuntime to the compiler.
You can't use a block as a cleanup value directly, since it has to be a function name, so (stealing ideas from here) you need to add a layer of indirection. Define a single function to clean up void blocks, and make your RAII'd variable the block that you want to run at the end of the scope:
typedef void (^cleanup_block)(void);
static inline void do_cleanup(cleanup_block * b) { (*b)(); }
void do_stuff(const char *name) {
cleanup_block __attribute__((cleanup(do_cleanup))) __b = ^{ };
}
Because blocks form closures, you can then place the operations on your variables to cleanup directly inside that block...
void do_stuff(const char *name) {
struct mything * thing;
cleanup_block __attribute__((cleanup(do_cleanup))) __b = ^{ ao2_cleanup(thing); };
}
...and that should run at the end of the scope as before, being invoked by the cleanup on the block. Rearrange the macro and add a __LINE__ so it works with multiple declarations:
#define CAT(A, B) CAT_(A, B)
#define CAT_(A, B) A##B
#define RAII_VAR(vartype, varname, initval, dtor) \
vartype varname = (initval); \
cleanup_block __attribute__((cleanup(do_cleanup))) CAT(__b_, __LINE__) = ^{ dtor(varname); };
void do_stuff(const char *name) {
RAII_VAR(struct mything *, thing, NULL, ao2_cleanup);
...
Something like that, anyway.
I believe you can do this without using a clang-specific version, I'd try something like this (untested, may require a few extra casts):
struct __destructor_data {
void (*func)(void *);
void **data;
}
static inline __destructor(struct __destructor_data *data)
{
data->func(*data->data);
}
#define RAII_VAR(vartype, varname, initval, dtor) \
vartype varname = initval; \
__attribute((cleanup(__destructor))) \
struct __destructor_data __dd ## varname = \
{ dtor, &varname };
In our project we have a gcc-specific _auto_(dtor) macro that precedes the normal variable declaration, e.g.:
_auto_(free) char *str = strdup("hello");
In this case our macro can't add anything after the variable declaration and also doesn't know the name of the variable, so to avoid using gcc-specific nested functions I came up with the following hackish version in case this helps anyone:
static void *__autodestruct_value = NULL;
static void (*__autodestruct_dtor)(void *) = NULL;
static inline void __autodestruct_save_dtor(void **dtor)
{
__autodestruct_dtor = *dtor;
__autodestruct_dtor(__autodestruct_value);
}
static inline void __autodestruct_save_value(void *data)
{
__autodestruct_value = *(void **) data;
}
#define __AUTODESTRUCT(var, func) \
__attribute((cleanup(__autodestruct_save_dtor))) \
void *__dtor ## var = (void (*)(void *))(func); \
__attribute((cleanup(__autodestruct_save_value)))
#define _AUTODESTRUCT(var, func) \
__AUTODESTRUCT(var, func)
#define _auto_(func) \
_AUTODESTRUCT(__COUNTER__, func)
This is hackish because it depends on the order the destructors are called by the compiler being the reverse of the order of the declarations, and it has a few obvious downsides compared to the gcc-specific version but it works with both compilers.
Building on the answers above, here's my hack to allow clang to compile nested procedures written in gcc-extension style. I needed this myself to support a source-to-source translator for an Algol-like language (Imp) which makes heavy use of nested procedures.
#if defined(__clang__)
#define _np(name, args) (^name)args = ^args
#define auto
#elif defined(__GNUC__)
#define _np(name, args) name args
#else
#error Nested functions not supported
#endif
int divide(int a, int b) {
#define replace(args...) _np(replace, (args))
auto int replace(int x, int y, int z) {
#undef replace
if (x == y) return z; else return x;
};
return a / replace(b,0,1);
}
int main(int argc, char **argv) {
int a = 6, b = 0;
fprintf(stderr, "a / b = %d\n", divide(a, b));
return 0;
}
struct Error
{
MACRO(1, Connect);
MACRO(2, Timeout);
};
I need to define MACRO() in such way that the above code will generate the following code.
struct Error
{
static const int Connect = 1;
static const int Timeout = 2;
const char * const name[] = {"Connect", "Timeout"};
};
Is this possible or what is the alternative to get what I'm trying to do?
You can't do this directly, but you can if you move the macros to a separate location (such as a separate file):
macros.hpp
MACRO(1, Connect)
MACRO(2, Timeout)
#undef MACRO
the other file
struct Error
{
#define MACRO(a, b) static const int b = a;
#include "macros.hpp"
const char * const name [] = {
#define MACRO(a, b) #b,
#include "macros.hpp"
}
};
Alternatively, you could achieve a similar effect with Boost.Preprocessor.
Here's a Boost.Preprocessor solution:
#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/seq/size.hpp>
#include <boost/preprocessor/tuple/elem.hpp>
#include <boost/preprocessor/stringize.hpp>
#define FIRST(a, b) a
#define SECOND(a, b) b
#define DECLARE_VAR(r, data, elem) \
static const int FIRST elem = SECOND elem;
#define NAME_ARRAY_ELEM(r, data, elem) \
BOOST_PP_STRINGIZE(FIRST elem),
#define MACRO(seq) \
BOOST_PP_SEQ_FOR_EACH(DECLARE_VAR, ~, seq) \
const char * const name[] = { \
BOOST_PP_SEQ_FOR_EACH(NAME_ARRAY_ELEM, ~, seq) \
}
int main()
{
MACRO(((Connect, 1))((TimeOut, 2)));
return 0;
}
You have to make sure to double bracket each ((Token, value)) pair, however you don't need a separate file for your macro.
What you want, is to have a single list, that will automatically generate the definition and the name list, correct?
If so, search for X Macros in google.
Example:
#define EXPAND_AS_DEFINITION(a, b) static const int b = a;
#define EXPAND_AS_ARRAY(a, b) #b,
#define STATE_TABLE(ENTRY) \
ENTRY(1, Connect) \
ENTRY(2, Timeout)
struct Error
{
STATE_TABLE(EXPAND_AS_DEFINITION)
static const char * const name[];
};
const char * const Error::name[] = {STATE_TABLE(EXPAND_AS_ARRAY) 0};
It looks like like you are trying to define an enum Error that also has the strings as members. I will give you my own solution to this problem. (I'm not addressing the question but I believe that my answer is relevant for what I understand that OP is trying to do.)
And I just realized that OP is targeting C, not C++, so not sure if this can be done...
In MyEnum.hpp
#define MYENUM(X,...) \
struct X { \
enum Enum {__VA_ARGS__}; \
static const std::vector<std::string> names; \
static X::Enum which(const std::string& s) { \
return static_cast<X::Enum>(findEnum(s,names)); \
} \
static std::string str(X::Enum i) { \
return names[i];} \
}
Here findEnum() is just a linear search over the vector that returns the position index (additionally, in my implementation if it doesn't find it it throws an exception with all the possible correct inputs, I also do case insensitive comparison). Note that an ordered map instead of a vector would be more efficient (O(log(n)) instead of O(n)), but I didn't cared much because the size of those things is very small in my case.
Below the previous macro, declare your enum as
MYENUM(Error,Connect,Timeout); // I put the semicolon here not in the macro
And in MyEnum.cpp, add
#include <boost/assign/list_of.hpp>
const std::vector<std::string> Error::names = boost::assign::list_of
("Connect")("Timeout");
(I think that it should be possible to use initialization lists with a modern compiler). The important thing here is to make sure that the order is the same, otherwise it will not work.
Then, you can do stuff like this:
Error::Enum err1 = Error::Connect;
Error::Enum err2 = Error::which("Timeout");
std::cout << "Got " << Error::str(err1) << " error. Not good.\n";
I read little gnu online docs about macro and little confused about this sentence:
Also multi-character operators such as += can be formed by token pasting
So I wander if macro can perform compound assignments,How?
#define PASTE(a,b) a##b
int foo;
foo PASTE(+,=) 2;
The only time I've ever seen this be useful was in the inner loop of a bytecode interpreter, which tends to look like a gigantic case statement with very repetitive code in each arm:
case OP_add: {
if (sp < 2) goto underflow;
double x = stack[--sp];
stack[sp-1] += x;
} break;
Repeat for each supported binary arithmetic operator. With the ability to token-paste, you can generate them all from a macro:
#define ARITH_BINOP(name, oper) case OP_##name: { \
if (sp < 2) goto underflow; \
double x = stack[--sp]; \
stack[sp-1] oper##= x; \
} break /* deliberate absence of semicolon */
and then, in the switch, you can just write
ARITH_BINOP(add, +);
ARITH_BINOP(sub, -);
ARITH_BINOP(mul, *);
/* etc */
I think, documentation says about cases like:
#define COMPST(x, y) x ## y
int
foo(int x)
{
return x COMPST(+, =) 2;
}
Of course macros can perform anything you can achieve in C code:
#define INCREMENT(x) ((x) += 1)
main() {
int n=42;
INCREMENT(n);
}
the line you read means another thing which I suspect you are not interested in...
FUNC(param);
When param is char *,dispatch to func_string.
when it's int,dispatch to func_int
I think there may be a solution to this,as variable types are known at compile time..
This will be possible with C1X but not in the current standard.
It will look like this:
#define cbrt(X) _Generic((X), long double: cbrtl, \
default: cbrt, \
float: cbrtf)(X)
Variable types are known to the compiler, but not to the preprocessor (which sees the code simply as unstructured text a stream of tokens, and performs only simple replacement operations on it). So I am afraid you can't achieve this with C macros.
In C++, they invented templates to solve such problems (and more).
You can test for the characteristics of the types.
For example, int can hold a negative value, while char* can't. So if ((typeof(param))-1) < 0, param is unsigned:
if (((typeof(param))-1) < 0) {
do_something_with_int();
} else {
do_something_with_char_p();
}
The compiler obviously optimizes this out.
Try it here: http://ideone.com/et0v1
This would be even easier if the types had different sizes. For example, if you want to write a generic macro than can handle different character sizes:
if (sizeof(param) == sizeof(char)) {
/* ... */
} else if (sizeof(param) == sizeof(char16_t)) {
/* ... */
} else if (sizeof(param) == sizeof(char32_t)) {
/* ... */
} else {
assert("incompatible type" && 0);
}
GCC has a __builtin_types_compatible_p() builtin function that can check for types compatibility:
if (__builtin_types_compatible_p(typeof(param), int)) {
func_int(param);
} else if (__builtin_types_compatible_p(typeof(param), char*)) {
func_string(param);
}
Try it here: http://ideone.com/lEmYE
You can put this in a macro to achieve what you are trying to do:
#define FUNC(param) ({ \
if (__builtin_types_compatible_p(typeof(param), int)) { \
func_int(param); \
} else if (__builtin_types_compatible_p(typeof(param), char*)) { \
func_string(param); \
} \
})
(The ({...}) is a GCC's statement expression, it allows a group of statements to be a rvalue.
The __builtin_choose_expr() builtin can choose the expression to compile. With __builtin_types_compatible_p this allows to trigger an error at compile-time if the type of param is not compatible with both int and char*: (by compiling somehting invalid in this case)
#define FUNC(param) \
__builtin_choose_expr(__builtin_types_compatible_p(typeof(param), int) \
, func_int(param) \
, __builtin_choose_expr(__builtin_types_compatible_p(typeof(param), char*) \
, func_string(param) \
, /* The void expression results in a compile-time error \
when assigning the result to something. */ \
((void)0) \
) \
)
This is actually a slightly modified example from __builtin_choose_expr docs.
There is no possibility to run time check types in C89 / ANSI C, but there is an extension to gcc which allows it. typeof or something along those lines if I remember. I saw it in the Linux Kernel once.
In kernel.h:
#define min(x, y) ({ \
typeof(x) _min1 = (x); \
typeof(y) _min2 = (y); \
(void) (&_min1 == &_min2); \
_min1 < _min2 ? _min1 : _min2; })
Take a look at this article: GCC hacks in the Linux kernel
When I first saw this I actually asked a question here on SO about:
min macro in kernel.h
I'm not quite sure exactly how you would use it to solve your problem, but it's something worth taking a look at.
You can't do this with a macro. Macro's value are substituted at compile time and are not intepreted. They are just substitutions.
Variable types are indeed known at compile time, however macro expansion takes place before compilation. I suggest you implement 2 overloaded functions instead of a macro.
my definition of a generic:
a structured abstract type which can only be fully defined with an input of other concrete types
this sounds exactly like a macro to me
pardon the psudo c code, my c is rusty
#include <stdio.h>
// todo: ret=self needs vec3##generic_t##_copy(self, ret);
// not to mention we should probably be using __builtin_add_overflow
// __builtin_add_overflow might actually itself be a reasonably generics method example
// please bear with me
#define GENERIC_VEC3_ADD(generic_t) \
generic_t vec3##generic_t##_add(generic_t self, generic_t other) {\
generic_t ret = self;\
ret[0] += other [0];;\
ret[1] += other [1];\
ret[2] += other [2];\
return ret;\
}
#define GENERIC_VEC3_FREPR(generic_t, printf_ts) \
int vec3##generic_t##_frepr(generic_t self, FILE fd)\
rerurn fprintf(fd, "<vec3##generic_t (##printf_ts##, printf_ts##, printf_ts##)>", \
self[0], self[1], self[2]);\
}
// here is the generic typedef, with some methods
#define GENERIC_VEC3(genetic_t, printf_ts) \
typedef vec3##generic_t generic_t[3];\
GENERIC_VEC3_ADD(generic_t) \
GENERIC_VEC3_FREPR(generic_t, printf_ts)
// later we decide what types we want this genic for
GENERIC_VEC3(int, %ul)
// and use our generic
int main()
{
vec3int foo = { 1, 2, 3 };;
vec3int bar = { 1, 2, 3 };;
vec3int sum = vec3int_add(foo, bar);
vec3int_frepr(sum, stderr);
fprintf(stderr, "\n");
exit EXIT_SUCCESS;
}