In general, C++ or C have no way of knowing what type of pointer you have.
The usual way to solve this problem is to make the pointer point to a struct, and have a known position in the struct indicate the type of the data. Usually the known position is the first position in the struct.
Example:
// signature value; use any value unlikely to happen by chance
#define VAR_SIG 0x11223344
typedef enum
{
vartypeInvalid = 0,
vartypeInt,
vartypeFloat,
vartypeDouble,
vartypeString,
vartypeMax // not a valid vartype
} VARTYPE;
typedef struct
{
VARTYPE type;
#ifdef DEBUG
uint32_t sig;
#endif // DEBUG
union data
{
int i;
float f;
double d;
char *s;
};
} VAR;
You can then do a sanity check: you can see if the type
field has a value greater than vartypeInvalid
and less than vartypeMax
(and you will never need to edit those names in the sanity check code; if you add more types, you add them before vartypeMax
in the list). Also, for a DEBUG
build, you can check that the signature field sig
contains some specific signature value. (This means that your init code to init a VAR
instance needs to always set the sig
field, of course.)
If you do something like this, then how do you initialize it? Runtime code will always work:
VAR v;
#ifdef DEBUG
v.sig = VAR_SIG;
#endif // DEBUG
v.type = vartypeFloat;
v.data = 3.14f;
What if you want to initialize it at compile time? It's easy if you want to initialize it with an integer value, because the int
type is the first type in the union
:
VAR v =
{
vartypeInt,
#ifdef DEBUG
VAR_SIG,
#endif // DEBUG
1234
};
If you are using a C99 compliant version of C, you can actually initialize the struct with a field name and have it assign any type. But Microsoft C isn't C99 compliant, so the above is a nightmare if you want to init your struct with a float
or double
value. (If you cast the float value to an integer, C won't just change the type, it will round the value; and there is no trick I know of to portably get a 32-bit integer value that correctly represents a 32-bit float at compile time in a C program.)
Compile time float packing/punning
If you are working with pointers, though, that's easy. Just make the first field name in the union be a pointer type, cast the pointer to void *
and init the struct as above (the pointer would go where 1234
went above).
If you are reading tables written by someone else's code, and you don't have a way to add a type identifier field, I don't have a general answer for you. I guess you could try reading the pointer out as different types, and see which one(s) work?