Two possible solutions using gcc extensions. The run-time version uses __builtin_types_compatible_p
and an assert
. The compile-time version is similar but uses a hack to get a static assert which fires at compile-time (albeit with a rather cryptic error message):
Run-time
#include <stdio.h>
#include <assert.h>
#define VOLATILE_MACRO(p) \
assert (__builtin_types_compatible_p(typeof(p), typeof(volatile int *)))
int main()
{
volatile int * x;
int * y;
VOLATILE_MACRO(x); // <<< OK
VOLATILE_MACRO(y); // <<< run-time error
return 0;
}
Compile-time
#include <stdio.h>
#include <assert.h>
#define A BUILD_NAME(__LINE__)
#define BUILD_NAME(line) BUILD_NAME2(line)
#define BUILD_NAME2(line) assert_ ## line
#define STATIC_ASSERT(test) typedef char A[(test) ? 1 : -1]
#define VOLATILE_MACRO(p) \
STATIC_ASSERT (__builtin_types_compatible_p(typeof(p), typeof(volatile int *)))
int main()
{
volatile int * x;
int * y;
VOLATILE_MACRO(x); // <<< OK
VOLATILE_MACRO(y); // <<< compile error
return 0;
}
Note that if you need to support other volatile
types then the macro can simply be extended with multiple chained __builtin_types_compatible_p
tests, e.g.
#define VOLATILE_MACRO(p) \
assert (__builtin_types_compatible_p(typeof(p), typeof(volatile int *)) ||
__builtin_types_compatible_p(typeof(p), typeof(volatile short *)))