I was trying to define a general function to take input using _Generic in C, This is what I wrote
#include <stdio.h>
#define readlong(x) scanf("%lld",&x);
#define read(x) scanf("%lld",&x);
#define scan(x) _Generic((x), \
long long: readlong, \
default: read \
)(x)
but when I compile it using gcc test.c -std=C11 on gcc 5.3.0, I get error:
error: 'readlong' undeclared (first use in this function)
You can define your helpers to be functions instead of macros. I modified scan so that it would pass the address to the matched function.
static inline int readlong (long long *x) { return scanf("%lld", x); }
static inline int readshort (short *x) { return scanf("%hd", x); }
static inline int unknown (void) { return 0; }
#define scan(x) _Generic((x), \
long long: readlong, \
short: readshort, \
default: unknown \
)(&x)
readlong
is not the variable that you have declared. In:
#define readlong(x) scanf("%11d",&x);
you added (x). This will not let you use readlong without them.
Related
My TLV structure can hold string or integer. I'm trying to create a macro that handles them both.
The example below runs as expected, but it compiles with warnings from the MACRO expansion. I understand the precompiler cannot know what type of value I'm going to assign at runtime, which is why I think it's raising the warning.
How can this little code snippet be fixed so it generates no compile warnings?
FWIW, I can code around this by not using the MACRO, but would prefer to use it if possible.
$ gcc -o simple{,.c} && ./simple
simple.c: In function ‘main’:
simple.c:25:21: warning: assignment makes pointer from integer without a cast [enabled by default]
tlv.value_str = (val); \
^
simple.c:38:3: note: in expansion of macro ‘TLV2STR_MACRO’
TLV2STR_MACRO(string, TYPE_INT, 11);
^
simple.c:28:21: warning: assignment makes integer from pointer without a cast [enabled by default]
tlv.value_int = (val); \
^
simple.c:41:3: note: in expansion of macro ‘TLV2STR_MACRO’
TLV2STR_MACRO(string, TYPE_STRING, "ELEVEN");
^
-----------------------------
INT : 11
STRING: ELEVEN
-----------------------------
#include <stdio.h>
typedef struct _tlv_s {
int type;
size_t length;
union _value {
int value_int;
char *value_str;
} value_u;
} tlv_t;
#define value_int value_u.value_int
#define value_str value_u.value_str
#define TYPE_STRING 0
#define TYPE_INT 1
#define TLV2STR_MACRO(s, t, val) { \
tlv_t tlv; \
tlv.type = (t); \
if (t == TYPE_STRING) { \
tlv.value_str = (val); \
sprintf(s, "STRING: %s", tlv.value_str); \
} else { \
tlv.value_int = (val); \
sprintf(s, "INT : %d", tlv.value_int); \
} \
}
int main(int argc, char *argv[])
{
char string[128];
printf("-----------------------------\n");
TLV2STR_MACRO(string, TYPE_INT, 11);
printf("%s\n", string);
TLV2STR_MACRO(string, TYPE_STRING, "ELEVEN");
printf("%s\n", string);
printf("-----------------------------\n");
}
How can this little code snippet be fixed so it generates no compile warnings?
You can add explicit casts.
tlv.value_str = (char*)(val); \
tlv.value_int = (int)(val); \
To your FWIW, such macro will not scale up, while it is fast to write for a toy example with two types and one use case, it will become painful and unreadable when more to come. Use virtual table with dispatch functions, keep your code readable, prefer not to use macros. I suggest removing confusing definitions #define value_int value_u.value_int and keeping your symbols within one namespace tlv_*. Do not end up with unreadable big switches, which your code seems to be going for. Prefer to use snprintf instead of sprintf.
I believe (glad to be proven otherwise) that it is not possible to pass values around as I had intended, casting them arbitrarily to string or integer.
Instead, passing pointers to values and casting the pointers is the proper way to do this. (As an aside, if this was truly a TLV implementation, it would handle any kind of structure, but this is just a dinky little app to demo the issue with passing values).
Notice that I modified the macro to accept a pointer to the value.
#include <stdio.h>
typedef struct _tlv_s {
int type;
size_t length;
union _value {
int value_int;
char *value_str;
} value_u;
} tlv_t;
#define value_int value_u.value_int
#define value_str value_u.value_str
#define TYPE_STRING 0
#define TYPE_INT 1
#define TLV2STR_MACRO(s, t, valp) { \
tlv_t tlv; \
tlv.type = (t); \
if (t == TYPE_STRING) { \
tlv.value_str = (char *)(valp); \
sprintf(s, "STRING: %s", tlv.value_str); \
} else { \
tlv.value_int = *(int *)(valp); \
sprintf(s, "INT : %d", tlv.value_int); \
} \
}
int main(int argc, char *argv[])
{
char string[128];
int val_int = 11;
printf("-----------------------------\n");
TLV2STR_MACRO(string, TYPE_INT, &val_int);
printf("%s\n", string);
TLV2STR_MACRO(string, TYPE_STRING, "ELEVEN");
printf("%s\n", string);
printf("-----------------------------\n");
}
And the output from compile and run....
$ gcc -o simple{,.c} && ./simple asdf
-----------------------------
INT : 11
STRING: ELEVEN
-----------------------------
I want to do "static dispatching" at compile-time via types.
Specifically, there is a family of functions (parameterized by type), and I want to select a function from that family (at compile-time) based on the type of an argument.
In C11, one can do this using _Generic().
For example, the following code works.
// gcc generic.c -o generic && ./generic
#include <stdio.h>
void foo_int() { printf("%s\n", __func__); } // Arbitrary code to show that this works
void foo_float() { printf("%s\n", __func__); } // Arbitrary code to show that this works
void foo_double(){ printf("%s\n", __func__); } // Arbitrary code to show that this works
#define foo_api0(VAL) \
_Generic(VAL, \
int: foo_int, \
float: foo_float, \
double: foo_double \
)()
int main(){
foo_api0(2);
foo_api0(4.f);
foo_api0(8.);
}
However, now suppose that, in the macro foo_api,
I don't want to pass a value of the desired type,
but I want to pass the desired type itself.
(The reasons why are not important for the current discussion. Assume such reasons exist.)
For example, instead of
foo_api0(2);
foo_api0(4.f);
foo_api0(8.);
I want to do
foo_api1(int);
foo_api1(float);
foo_api1(double);
One can achieve this by using the type itself to create an auxiliary variable (ie. a "witness" of the type):
#define foo_api1(TYPE) ({ \
TYPE witness; \
_Generic(witness, \
int: foo_int, \
float: foo_float, \
double: foo_double \
)(); \
})
and then both APIs work:
int main(){
foo_api0(2);
foo_api0(4.f);
foo_api0(8.);
foo_api1(int);
foo_api1(float);
foo_api1(double);
}
My question is:
Is there a way of doing this without using such an auxiliary variable?
(Perhaps there's a macro/keyword in C that can do stuff based on a type itself, rather than on a variable of that type?)
For example, it'd be nice to have something like:
#define foo_api1(TYPE) ({ \
_Generic(TYPE, \
int: foo_int, \
float: foo_float, \
double: foo_double \
)(); \
})
to pass the desired type itself.
Form a compound literal: (TYPE){0}
#define foo_api1(TYPE) \
_Generic((TYPE){0}, \
int: foo_int, \
float: foo_float, \
double: foo_double \
)()
int main(){
foo_api1(int);
foo_api1(float);
foo_api1(double);
}
To address #Eric Postpischil comment:
Form a compound literal as a pointer: (TYPE *){0}
#define foo_api2(TYPE) \
_Generic((TYPE *){0}, \
int *: foo_int, \
float *: foo_float, \
double *: foo_double \
)()
I have a template like this:
template.h
----------
// Declare a function "func_type()"
void JOIN(func_, T)(T t) { return; }
#undef T
which I use like this in order to generate the same function for different types:
example.c
---------
#define T int
#include "template.h"
#define T float
#include "template.h"
I would like to have a single func that I can use instead of funct_int, func_float, etc. My problem with _Generic is that it doesn't seem possible to define the association-list dynamically. In practical terms I'd like to have something like this:
#define func(TYPE) _Generic((TYPE), AUTO_GENERATED_LIST)
instead of manually defining every new type like this:
#define func(TYPE) _Generic((TYPE), int: func_int..., float: func_float...)
Here's an example of code that is not working: https://ideone.com/HN7sst
I think what you want to do can be achieved with the dreaded "X macros". Create a list such as
#define SUPPORTED_TYPES(X) \
X(int, "%d") \
X(float, "%f") \
where int is the type and in this case I used printf format specifier as another item. These can be anything that counts as valid pre-processor tokens.
Then you can generate all functions through an evil macro like this:
#define DEFINE_F(type, fmt) \
void f_##type (type param) \
{ printf(fmt "\n", param); }
SUPPORTED_TYPES(DEFINE_F)
This creates functions such as void f_int (int param) { printf("%d\n", param); }. That is, very similar to C++ templates - functions doing the same thing but with different types.
You can then write your _Generic macro like this:
void dummy (void* param){}
#define GENERIC_LIST(type, fmt) type: f_##type,
#define func(x) _Generic((x), SUPPORTED_TYPES(GENERIC_LIST) default: dummy)(x)
Here you define the generic asoc. list with GENERIC_LIST, using the type item but ignoring everything else. So it expands to for example int: f_int,.
A problem with this is the old "trailing comma" problem, we can't write _Generic like _Generic((x), int: f_int,)(x) the comma after f_int would mess up the syntax. I solved this with a default clause calling a dummy function, not ideal... might want to stick an assert inside that function.
Full example:
#include <stdio.h>
#define SUPPORTED_TYPES(X) \
X(int, "%d") \
X(float, "%f") \
#define DEFINE_F(type, fmt) \
void f_##type (type param) \
{ printf(fmt "\n", param); }
SUPPORTED_TYPES(DEFINE_F)
void dummy (void* param){}
#define GENERIC_LIST(type, fmt) type: f_##type,
#define func(x) _Generic((x), SUPPORTED_TYPES(GENERIC_LIST) default: dummy)(x)
int main (void)
{
int a = 1;
float b = 2.0f;
func(a);
func(b);
}
Output:
1
2.000000
This is 100% ISO C, no extensions.
I want to use the C11 _Generic keyword to fill an union according to the static type, like:
typedef union {
double d;
long l;
const char*s;
void*p;
} ty;
#define make_ty(X) _Generic((X), \
double: (ty){.d=(X)}, \
long: (ty){.l=(X)}, \
const char*: (ty){.s=(X)}, \
default: (ty){.p=(X)})
ty from_double(double x) { return make_ty(x); }
ty from_string(const char*s) { return make_ty(s); }
ty from_long(long l) { return make_ty(l);}
but this does not compile, e.g. GCC 5.3 gives (with gcc -std=c11 -Wall):
u.c: In function ‘from_double’:
u.c:11:35: error: incompatible types when initializing type ‘const char *’
using type ‘double’
const char*: (ty){.s=(X)}, \
^
u.c:14:41: note: in expansion of macro ‘make_ty’
ty from_double(double x) { return make_ty(x); }
BTW, using gcc -std=c99 -Wall gives the same error...
Or is _Generic only useful for tgmath.h ?
I thought that _Generic chooses the expression according to the compiler-known type, so the non-sensical (ty){.s=(x)} would be ignored in from_double....
(if that did work, I would be able to "overload" make_ty according the static, compiler-known, type of the argument...)
All branches of _Generic must be valid code, just as much as in something like if (1) { here; } else { there; }. To have a solution you could take it the other way around. Define functions similar to:
inline ty from_double(double x) { return (ty){ .d = x }; }
for all your cases and then have the macro as:
#define make_ty(X) _Generic((X), \
double: from_double, \
double: from_long, \
...)(X)
With the visibility through inline compilers are actually able to optimize such code and will usually not pass through calling the function pointer.
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;
}