Reputation: 13
Generic o(X) is used to construct Object from several types. But GCC don't expands to typedef types.
warning: passing argument 1 of ‘oBytes’ from incompatible pointer type [-Wincompatible-pointer-types]
68 | Object ovi = o(vi);
| ^~
| |
| HashTable {aka struct _HashTable *}
../cedata.h:13:43: note: in definition of macro ‘o’
13 | char : oBytes( X , 1), \
|
_Generic definition of o(x):
#define o( X ) _Generic ((X), \
char : oBytes( X , 1), \
char * : oNewFrom(STRING, X), \
unsigned char * : oNewFrom(STRING, X), \
int : oNewFrom(INT, X), \
float : oNewFrom(FLOAT, X), \
short : oNewFrom(SHORT, X), \
HashTable : oNewFrom(HASHTABLE,X), \
List : oNewFrom(LIST, X), \
default : oNew() \
)
All oNewFrom and oBytes return Object.
When vi
which type is HashTable
aka struct _HashTable *
is used with this Generic at line Object ovi = o(vi);
gcc call char : oBytes( X , 1),
instead HashTable : oNewFrom(HASHTABLE,X),
.
I made any mistake or Generic don't work with structs and typedefs?
Upvotes: 1
Views: 903
Reputation: 5830
Since you have a definition for every type, you could specify the calling convention to be the same for all types.
For example:
create_xxx(void *obj);
//xxx stands for the different types
Then your generic macro:
#define o(X) _Generic((X), \
type1: create_type1(X), \
type2: create_type2(X), \
...
Since the argument for the create function is an opaque pointer, the compiler will never complain about what you're passing to the function. And your function knows how to deal with the data at that address.
--- Based on your comment ---
Since i don't know exactly what you're trying to accomplish, i only provided the base usage of generics and how to avoid the given warnings.
Minimal executable code of what i meant:
#include <stdlib.h>
#include <stdio.h>
typedef struct ObjectRec {
int id;
} Object;
void* create_int(void *ptr)
{
printf("create_int\n");
return ptr;
}
void* create_float(void *ptr)
{
printf("create_float\n");
return ptr;
}
void* create_obj(void *ptr)
{
printf("create_obj\n");
((Object*) ptr)->id = 0;
return ptr;
}
#define o(X) _Generic((X), \
int*: create_int, \
float*: create_float, \
Object*: create_obj \
)(X)
int main()
{
int i = 1;
float f = 0.5f;
Object obj;
o(&i);
o(&f);
o(&obj);
return EXIT_SUCCESS;
}
Might (also) be of interest:
Upvotes: 0
Reputation: 153517
Sadly, with _Generic
, each expression needs to make compilation sense for the type, not only the one that is used.
#define o( X ) _Generic ((X), \
char : oBytes( X , 1), \
...
HashTable : oNewFrom(HASHTABLE,X), \
...
)
HashTable vi; ... o(vi)
does not compile because oBytes( X , 1)
when X
is a HashTable
does not compile, even though that line is not selected.
With int, void *, double, ...
, conversion is defined between the types. Yet with HashTable
as a struct
, there lacks conversion to/from basic types.
I'd consider posting an alterative, yet OP's post lacks details to embark on that effort.
A typical alterative passes the address of X
to the various functions.
Upvotes: 2