You can tell them apart at the cost of a compilation failure. int and
long are compatible for most purposes, but int* and long* are not. If
you have a typedef T that could be either int or long, then of these
two expressions:
(T*)0 == (int*)0
(T*)0 == (long*)0
one will compile and one will not (more precisely one is a constraint
violation requiring a diagnostic).
This could be useful for some kind of pre-compilation configuration
system, but I can't think of any way to use it within a single legal
program.
It could be used to verify that a macro invocation with both type and
identifier as parameters used the correct type, to some extent.
Given that C does not preserve type information in the result of
translation (so it's not available at runtime), nor provide a
mechanism for obtaining an identifier's type during translation (so
it's not available at compile time), the only way to achieve some-
thing like what the OP is asking for is to explicitly supply the type
to the macro.
To reduce error it would then be useful (assuming there's any utility
at all to the exercise) to validate the supplied type.
So:
-----
#include <stdio.h>
#define DO_STRINGIZE(x) #x
#define STRINGIZE(x) DO_STRINGIZE(x)
#define PRINT_TYPE(type,id) \
{ type * t##id = & id; \
puts("Type of " STRINGIZE(id) " is " STRINGIZE(type)); }
int main(void)
{
int i;
long l;
const char *p;
PRINT_TYPE(int, i);
PRINT_TYPE(long, l);
PRINT_TYPE(const char *, p);
return 0;
}
-----
Since this relies on a useful diagnostic from the implementation,
though, it's a bit hit-or-miss.
--
Michael Wojcik (e-mail address removed)
Reversible CA's are -automorphisms- on shift spaces. It is a notorious
fact in symbolic dynamics that describing such things on a shift of finite
type are -fiendishly- difficult. -- Chris Hillman