The problem is that C doesn’t treat your two typedefs as distinctive types, because they are both type unsigned
.
There are various tricks to dodge this. One thing would be to change your types to enums. Good compilers will enforce stronger typing warnings on implicit conversions to/from a certain enum type to any other type.
Even if you don’t have a good compiler, with enums you could do this:
typedef enum { FOO_CENT } cent_t;
typedef enum { FOO_DOLLAR} dollar_t;
#define DOLLAR_2_CENT(dollar) ((cent_t)(100*(dollar)))
void calc(cent_t amount) {
// expecting 'amount' to semantically represents cents...
}
#define type_safe_calc(amount) _Generic(amount, cent_t: calc(amount))
int main(int argc, char* argv[]) {
dollar_t amount = 50;
type_safe_calc(DOLLAR_2_CENT(amount)); // ok
type_safe_calc(amount); // raise warning
return 0;
}
A more conventional/traditional trick is to use a generic struct wrapper, where you use a “ticket” enum to mark the type. Example:
typedef struct
{
type_t type;
void* data;
} wrapper_t;
...
cent_t my_2_cents;
wrapper_t wrapper = {CENT_T, &my_2_cents};
...
switch(wrapper.type)
{
case CENT_T: calc(wrapper.data)
...
}
The advantage is that it works with any C version. Disadvantage is code and memory overhead, and that it only allows run-time checks.