I'm trying to do a type check at compile time in one of my macros. The simplified code looks something like this:
I have a structure consisting of:
an int representing a type of a function interface and
a generic function pointer
typedef void(*generic_func_t)(void);
typedef struct
{
int type;
generic_func_t function;
} func_def_t;
to initialize this structure I have defined two macros;
#define INIT_FUNC1_TYPE(function) {1, (generic_func_t)function}
#define INIT_FUNC2_TYPE(function) {2, (generic_func_t)function}
The usage would be something like this:
int(*func1_t)(int, int, int);
int(*func2_t)(int, int);
int foo(int a, int b)
{
return a + b;
}
func_def_t active_func = INIT_FUNC2_TYPE(foo);
...
int a = 2;
int b = 3;
int c = 4;
int d;
if (active_func.type == 1)
{
func1_t func = (func1_t)active_func.function;
d = func(a, b, c);
}
if (active_func.type == 2)
{
func2_t func = (func2_t)active_func.function;
d = func(a, b);
}
My problem now is that any type of function can be cast to (void*).
But it must somehow be possible to design the macro in such a way that only a certain type of function-interface is accepted by the compiler. Maybe with typeof?
Let's say there are the function types:
void(*func1_t)(int, int, int);
int(*func2_t)(float, int);
How can I do that?
Edited:
I changed the pointer from void* to generic_func_t but the essence of the questions stays the same. The macro INIT_FUNC1_TYPE should only accept functions with an interface like func1_t. The macro INIT_FUNC2_TYPE should only accept functions with an interface like func2_t.
I have a structure consisting of:
an int representing a type of a function interface and
a void pointer to the function
No, you haven't, because a void * points to an object not a function. However, you can convert freely (via typecast) among function pointer types, so you can choose any bona fide function pointer type for your purpose. Perhaps void (*)(void):
typedef struct {
int type;
void (*function)(void);
} func_def_t;
You will need to convert back to the correct function pointer type to call the function anyway, so this is no harder to use than void *.
My problem now is that any type of function can be cast to (void*).
Well, no type of function pointer can be cast to void * by a strictly conforming program. But if your compiler accepts such conversions as an extension then yes, presumably it works for any function pointer type. And so does converting from any function pointer type to any other function pointer type, including in strictly conforming programs.
But it must somehow be possible to design the macro in such a way that only a certain type of function-interface is accepted by the compiler. Maybe with typeof?
Standard C does not have typeof, though I believe it's scheduled for inclusion in C23. But I don't think that helps you.
However, you can use a type-generic expression in your macro to limit it to certain function pointer types. In fact, that could allow you to have a single macro instead of two.
Per-type example:
typedef void (func)(void);
typedef struct {
int type;
func *function;
} func_def_t;
#define INIT_FUNC1_TYPE(f) {1, _Generic((f), void (*)(int, int, int) : (func *) f) }
#define INIT_FUNC2_TYPE(f) {2, _Generic((f), int (*)(float, int) : (func *) f) }
The compiler will object if one of those macros is invoked with an argument that does not match one of the type names in the _Generic selection within, and each of those affords exactly one option.
But that misses out on the opportunity to do everything with a single macro. Consider this:
#define INIT_FUNC_TYPE(f) { \
.type = _Generic((f), \
void (*)(int, int, int) : 1, \
int (*)(float, int) : 2), \
.function = (func *) f \
}
Now the (one) macro chooses the function-type key based on the type of the macro argument (and the compiler rejects arguments that don't match any of the specified types). This scales better than an approach requiring a separate macro for each supported function signature.
Macros in C are simple text replacements and completely oblivious to C types. If you want type checking, you'll have to declare the member of the struct as a function pointer, like so
typedef struct
{
int type;
void *(function) (int,int,int);
} func_def_t;
Related
For a project I'm working on, it's desirable to have a generic "pointer to a function" type. However, in C, to have a pointer to a function, you need to specify the prototype in the type of the function pointer.
For example, if I have the function void setdata(short data), I can't store that in the same pointer as I would a function int getdata(), because their arguments and return values are different.
After some lateral thinking, I came up with the following workaround:
typedef long (* PFL)(); /* pointer to function that returns a long... */
typedef short (* PFI)(); /* pointer to function that returns a short... */
typedef void (* PFV)(); /* pointer to function that returns a void... */
typedef void (* PFVAL)(long); /* pointer to function that returns a void...
but has a long argument...*/
typedef void (* PFVAI)(short); /* pointer to function that returns a void...
but has an short argument...*/
typedef void (* PFVAU)(unsigned short);
typedef void (* PFVAII)(short, short); /* same as above, but two shorts... */
typedef void (* PFVAUU)(unsigned short, unsigned short); /* same as above, but two shorts... */
typedef union {
PFV pfv;
PFI pfi;
PFL pfl;
PFVAL pfval;
PFVAI pfvai;
PFVAU pfvau;
PFVAII pfvaii;
PFVAUU pfvauu;
} FP;
Sure enough, I'm able to initialize instances of this type like so:
FP funcpointer = { .pfvai = setdata };
Clang and GCC don't complain. Is this a bad idea?
What you're doing is valid. As long as you're calling the pointed-to function via the proper pointer type, it's well defined.
This union could get big however depending on how many different function types you have to support, and you have to keep it in sync with your set of typedefs. As it turns out you can freely convert from one function pointer type to another via a cast, you just need to make sure you call it with the proper type.
Section 6.3.2.3p8 of the C standard say the following about function pointer conversions:
A pointer to a function of one type may be converted to a pointer to a function of another type and back again; the result shall compare equal to the original pointer. If a converted pointer is used to call a function whose type is not compatible with the referenced type, the behavior is undefined.
So you could also just use void (*)() as a generic pointer type instead of using a union, then you would need to apply the proper cast when you call it. For example:
typedef void (*FP)();
FP fp = setdata;
...
((PFVAI)fp)(123);
This can be fun, and I've used the pattern below plenty of times in pure C projects.
The idea is to collect all information about what you want to set up in a single "table", and then run the contents of this table through various macro "functions".
#define WITH_FUNP_MEMBERS \
ON_FUNP_MEMBER(0, PFV, void, void) \
ON_FUNP_MEMBER(1, PFL, long, void) \
ON_FUNP_MEMBER(2, PFS, short, void) \
ON_FUNP_MEMBER(3, PFI, int, void) \
ON_FUNP_MEMBER(4, PFVL, void, long) \
ON_FUNP_MEMBER(5, PFVS, void, short) \
ON_FUNP_MEMBER(6, PFVI, void, int) \
ON_FUNP_MEMBER(7, PFVSS, void, short, short)
// NAME_tag: Tags
enum Type_Tag { void_tag = 0, long_tag, short_tag, int_tag };
#define ON_FUNP_MEMBER(id, NAME, ret, ...) NAME##_tag = ret##_tag << 8 | id,
enum FUNP_Tag { WITH_FUNP_MEMBERS };
#undef ON_FUNP_MEMBER
// NAME_ret: Return Types
#define ON_FUNP_MEMBER(id, NAME, ret, ...) typedef ret NAME##_ret;
WITH_FUNP_MEMBERS
#undef ON_FUNP_MEMBER
// NAME: Function Pointer Types
#define ON_FUNP_MEMBER(id, NAME, ret, ...) typedef ret(*NAME)(__VA_ARGS__);
WITH_FUNP_MEMBERS
#undef ON_FUNP_MEMBER
// Functor
#define ON_FUNP_MEMBER(id, NAME, ret, ...) NAME p_##NAME;
struct {
union {
WITH_FUNP_MEMBERS // PFV p_PFV; PFL p_PFL; ...
};
enum FUNP_Tag tag;
} typedef Functor;
#undef ON_FUNP_MEMBER
Now we can produce some type-safe setters, where the type of the function being assigned is captured in the name of the setter. The compiler will warn if a function of the wrong type is assigned.
// Setter Declarations
#define ON_FUNP_MEMBER(id, NAME, ret, ...) \
void FUNP_Set_##NAME(Functor *f, NAME arg);
WITH_FUNP_MEMBERS
#undef ON_FUNP_MEMBER
// Setter Definitions
#define ON_FUNP_MEMBER(id, NAME, ret, ...) \
void FUNP_Set_##NAME(Functor *f, NAME arg) { \
f->tag = NAME##_tag; \
f->p_##NAME = arg; \
}
WITH_FUNP_MEMBERS
#undef ON_FUNP_MEMBER
Now we can declare a convenient functor initializer, and the invoker. The invoker is type-safe, and will not call the functor if its type doesn't match the NAME passed to invoker.
// Invoker Helpers
static inline int FUNP__set_ok(void* ok) { if (ok) *(int*)ok = 1; }
static inline int FUNP__clr_ok(void *ok) { if (ok) *(int*)ok = 0; }
// Functor Initializer
// Example: Functor f = FUNP_INIT(PFI, my_int_function);
#define FUNP_INIT(NAME, function) {.p_##NAME = (function), .tag = NAME##_tag}
// Functor Invoker
// Example: return FUNP_INVOKE(PFI, &f, NULL) [returns an integer]
#define FUNP_INVOKE(NAME, f, ok, ...) \
(((f) && (f)->tag == NAME##_tag && (f)->p_##NAME) ? (FUNP__set_ok(ok), (f)->p_##NAME(__VA_ARGS__)) : (NAME##_ret)FUNP__clr_ok(ok))
And finally:
// Test
#include <assert.h>
#include <stdio.h>
int fun1(void) { return 42; }
void fun2(int i) { printf("%d\n", i); }
int main()
{
Functor f = FUNP_INIT(PFI, fun1);
int value = FUNP_INVOKE(PFI, &f, NULL);
assert(value == 42);
int ok = 0;
FUNP_INVOKE(PFI, &f, &ok);
assert(ok);
FUNP_INVOKE(PFVI, &f, &ok, value); // type mismatch
assert(!ok);
FUNP_Set_PFVI(&f, fun2);
FUNP_INVOKE(PFVI, &f, NULL, value);
}
I want to manage various entities with the same "universal" functions. The entities are schematically declared as:
typedef struct {
prefix_t pfx;
int i1;
int i2;
int i3;
} entity_t;
i.e. a typedef'd struct prefix for housekeeping (containing chaining pointers, flags, etc.) and a payload. There is one such type declaration per entity type.
The housekeeping functions need only to get a pointer to the prefix, which is easy, and a function which will "explore" the payload to return a meaningful quantity for the housekeeping.
With the example of binary tree management:
void TreeInsert (prefix_t *a, prefix_t *b, int (*compare) (prefix_t *, prefix_t *));
And inside the procedure, I have a call like this:
if (0 > compare(a, b)) {
// a comes before b
} else {
// a is the same as b or comes after
};
That's fine. The library function compiles without error nor warning.
But it is obvious that the compare function can't only reference the prefix. It needs to probe the payload to be useful:
int comp_entity (entity_t *a, entity_t *b) {
return a->i1 - b->i1;
}
The compiler gives warning for comp_entity on the following line:
TreeInsert (&a->pfx, &b->pfx, comp_entity);
Since the library function is used for many different "entities", the compare function cannot be typecast at time of call. The arguments to the compare function cannot be typed for the prefix otherwise there is no means to access the payload.
Should I define a specific function type only for the purpose of passing the compare to the library function? Something like:
typedef int (func_cast *) (prefix_t *, prefix_t*);
and
TreeInsert (&a->pfx, &b->pfx, (func_cast)comp_entity);
I'd rather avoid this. Is this possible?
Nota:
I have found create universal function pointer to any type C language and How do I quiet the C compiler about a function pointer takes any number of arguments?, but they don't provide a solution.
Your compare function knows what the true type should be, so you would declare the arguments with type prefix_t * and cast the arguments inside of the function:
int comp_entity (prefix_t *a, prefix_t *b) {
entity_t *ea = (entity_t *)a;
entity_t *eb = (entity_t *)b;
return ea->i1 - eb->i1;
}
Suppose we have a function like this:
void WonderfulFunction(float a)
Clearly, we can pass an int to wonderful_function and the C-compiler will promote the int to a float.
However, what about user-defined data types? Suppose we use a typedef statement to give a name/alias to a struct. Is there some way to define a promotion-rule, casting function, or constructor which will automatically convert a primitive to ADT (abstract data type)? I realize this can be done in C++, but this needs to be in C.
We want something like the following code to compile correctly:
// #include <niffty_promoter_castOperator_thing.h>
struct HappyStruct {
int happy_int;
};
typedef struct HappyStruct HappyStruct;
/* prototype */
void AnotherWonderfulFunction(HappyStruct hs)
int main( ) {
int a = 12345;
AnotherWonderfulFunction(a);
// A caster/promoter included in the
// header file specifies how to
// construct a HappyStruct from an int
return 0;
}
void AnotherWonderfulFunction(HappyStruct hs) {
// do stuff;
}
This is "possible" with generic selection (YMMV); this described here is the closest you can get in C11. (In C99, C89 this is not possible at all). Here, AnotherWonderfulFunction(X) is a macro that will expand to (AnotherWonderfulFunction)(AsHappy(X)); the parentheses ensure that the macro is not recursively expanded.
AsHappy(X) is a macro that uses generic selection to choose one from 2 utility functions - HappyAsIs takes a struct HappyStruct as a parameter and returns it as-is, whereas HappyFromInt expects an int argument, and will return it wrapped in a struct. It needs to be done using utility functions, because at least GCC does check the language constraints for other branches, even though they're not evaluated. The original X is then passed to the selected function as an argument.
#include <stdio.h>
struct HappyStruct {
int happy_int;
};
void AnotherWonderfulFunction(struct HappyStruct hs) {
printf("AnotherWonderfulFunction called with hs.happy_int = %d\n", hs.happy_int);
}
struct HappyStruct HappyAsIs(struct HappyStruct s) {
return s;
}
struct HappyStruct HappyFromInt(int val) {
return (struct HappyStruct){ val };
}
#define AsHappy(X) \
_Generic((X), \
struct HappyStruct: HappyAsIs, \
default: HappyFromInt \
)(X)
#define AnotherWonderfulFunction(X) (AnotherWonderfulFunction)(AsHappy(X))
int main(void) {
int a = 42;
float b = 65536.5;
struct HappyStruct c = { 123 };
AnotherWonderfulFunction(a);
AnotherWonderfulFunction(b);
AnotherWonderfulFunction(c);
}
and running the program produces:
% ./a.out
AnotherWonderfulFunction called with hs.happy_int = 42
AnotherWonderfulFunction called with hs.happy_int = 65536
AnotherWonderfulFunction called with hs.happy_int = 123
However, the magic disappears as soon as you take a pointer to a function;
void (*fp)(struct HappyStruct) = AnotherWonderfulFunction;
now of course fp cannot work that way because it is not a macro.
... until you make it one ...
#define fp(X) (fp)(AsHappy(X))
All this is somewhat useless, since C11 supports compound literals:
AnotherWonderfulFunction((struct HappyStruct){ 42 });
so it is of limited use - lots of black magic to save a few keystrokes.
For cases where you only care about the binary representation (i.e., not in the int-to-float case), you can use GCC's __attribute__((transparent_union))
I want to convert the libusb.h into PureBasic code and now I have this line:
typedef void (LIBUSB_CALL *libusb_transfer_cb_fn)(struct libusb_transfer *transfer);
What does this typedef do?
Later on there are lines like this:
void LIBUSB_CALL libusb_free_device_list(libusb_device **list, int unref_devices);
Thanks in advance!
LIBUSB_CALL is just a type annotation. It probably doesn't do anything.
This declares a type "f" that is a function pointer returning void and taking "params":
typedef void (*f)(params...)
libusb_transfer_cb_fn is a type representing a function pointer tacking a pointer to a libusb_transfer struct and returning nothing (void).
The syntax for typedef in C is peculiar. What you do is write an ordinary declaration:
int x, *y, z[2];
and then insert the keyword typedef in front. This tells the compiler that, for each variable declared, don't actually declare a variable; instead, make that a new name for the type that the variable would have had, if it were a variable. So:
typedef int x, *y, z[2];
makes x an alias for int, y an alias for int *, and z an alias for int [2].
If you take the typedef off the original line you get:
void (LIBUSB_CALL *libusb_transfer_cb_fn)(struct libusb_transfer *transfer);
(which is only syntactically valid if LIBUSB_CALL is a macro, probably some compiler-specific modifier like __stdcall or __fastcall), which is already a little peculiar because of C's need to parenthesize pointers-to-functions. But it would declare (and define) libusb_transfer_cb_fn as a variable of type "pointer to function taking one argument (the transfer thing) and returning void. So the typedef makes libusb_transfer_cb_fn an alias for that type.
The name obviously (well... :-) ) means: "callback function for libusb after a transfer operation".
The idea would be that a later bit of C code might read something like:
extern libusb_transfer_cb_fn abc_func;
which tells you that there's some global variable abc_func of type "pointer to libusb callback", or:
some_return_type xyz_func(libusb_transfer_cb_fn funcp, int a, char *b) {
struct libusb_transfer x;
... some code that fills in x ...
(*funcp)(&x);
}
I have to define a 24-bit data type.I am using char[3] to represent the type. Can I typedef char[3] to type24? I tried it in a code sample. I put typedef char[3] type24; in my header file. The compiler did not complain about it. But when I defined a function void foo(type24 val) {} in my C file, it did complain. I would like to be able to define functions like type24_to_int32(type24 val) instead of type24_to_int32(char value[3]).
The typedef would be
typedef char type24[3];
However, this is probably a very bad idea, because the resulting type is an array type, but users of it won't see that it's an array type. If used as a function argument, it will be passed by reference, not by value, and the sizeof for it will then be wrong.
A better solution would be
typedef struct type24 { char x[3]; } type24;
You probably also want to be using unsigned char instead of char, since the latter has implementation-defined signedness.
You want
typedef char type24[3];
C type declarations are strange that way. You put the type exactly where the variable name would go if you were declaring a variable of that type.
From R..'s answer:
However, this is probably a very bad idea, because the resulting type
is an array type, but users of it won't see that it's an array type.
If used as a function argument, it will be passed by reference, not by
value, and the sizeof for it will then be wrong.
Users who don't see that it's an array will most likely write something like this (which fails):
#include <stdio.h>
typedef int twoInts[2];
void print(twoInts *twoIntsPtr);
void intermediate (twoInts twoIntsAppearsByValue);
int main () {
twoInts a;
a[0] = 0;
a[1] = 1;
print(&a);
intermediate(a);
return 0;
}
void intermediate(twoInts b) {
print(&b);
}
void print(twoInts *c){
printf("%d\n%d\n", (*c)[0], (*c)[1]);
}
It will compile with the following warnings:
In function ‘intermediate’:
warning: passing argument 1 of ‘print’ from incompatible pointer type [enabled by default]
print(&b);
^
note: expected ‘int (*)[2]’ but argument is of type ‘int **’
void print(twoInts *twoIntsPtr);
^
And produces the following output:
0
1
-453308976
32767
Arrays can't be passed as function parameters by value in C.
You can put the array in a struct:
typedef struct type24 {
char byte[3];
} type24;
and then pass that by value, but of course then it's less convenient to use: x.byte[0] instead of x[0].
Your function type24_to_int32(char value[3]) actually passes by pointer, not by value. It's exactly equivalent to type24_to_int32(char *value), and the 3 is ignored.
If you're happy passing by pointer, you could stick with the array and do:
type24_to_int32(const type24 *value);
This will pass a pointer-to-array, not pointer-to-first-element, so you use it as:
(*value)[0]
I'm not sure that's really a gain, since if you accidentally write value[1] then something stupid happens.
To use the array type properly as a function argument or template parameter, make a struct instead of a typedef, then add an operator[] to the struct so you can keep the array like functionality like so:
typedef struct type24 {
char& operator[](int i) { return byte[i]; }
char byte[3];
} type24;
type24 x;
x[2] = 'r';
char c = x[2];
Here's a short example of why typedef array can be confusingly inconsistent. The other answers provide a workaround.
#include <stdio.h>
typedef char type24[3];
int func(type24 a) {
type24 b;
printf("sizeof(a) is %zu\n",sizeof(a));
printf("sizeof(b) is %zu\n",sizeof(b));
return 0;
}
int main(void) {
type24 a;
return func(a);
}
This produces the output
sizeof(a) is 8
sizeof(b) is 3
because type24 as a parameter is a pointer. (In C, arrays are always passed as pointers.) The gcc8 compiler will issue a warning by default, thankfully.
Building off the accepted answer, a multi-dimensional array type, that is a fixed-length array of fixed-length arrays, can't be declared with
typedef char[M] T[N]; // wrong!
instead, the intermediate 1D array type can be declared and used as in the accepted answer:
typedef char T_t[M];
typedef T_t T[N];
or, T can be declared in a single (arguably confusing) statement:
typedef char T[N][M];
which defines a type of N arrays of M chars (be careful about the order, here).