12

是否有一些“好”的方法来检查传递给宏的变量是否是指针?例如

#define IS_PTR(x) something
int a;
#if IS_PTR(a)
printf("a pointer we have\n");
#else
printf("not a pointer we have\n");
#endif

这个想法是,这不是在运行时而是在编译时完成的,例如:根据变量是否为指针,我们得到不同的代码。所以我希望 IS_PTR() 以某种方式评估为某种常量表达式。我是否以错误的方式提出这个想法?

4

5 回答 5

6

#if正如您在问题中暗示的那样,它肯定无法通过预处理器观察到。预处理器对类型一无所知,只知道由它们构造的标记和表达式。

C11 有一个新功能,可以让您观察特定的指针类型,但不是一般的“指针”。例如,你可以做某事

#define IS_TOTOP(X) _Generic((X), default: 0, struct toto*: 1)

或者如果您希望宏也适用于数组

#define IS_TOTOPA(X) _Generic((X)+0, default: 0, struct toto*: 1)

周围已经有一些编译器实现了这一点,即 clang,对于 gcc 和其他编译器,您已经可以使用一些内置函数来模拟该功能,请参阅P99

于 2013-10-08T18:20:10.407 回答
3

NULL 几乎是您唯一可以寻找的东西。没有办法确定某物是否是指针。

于 2013-10-08T18:15:28.090 回答
3

我或多或少地找到了_Generic这个问题的解决方案。

警告:可能会触发误报(参见下面的示例)。

#define __INTERNAL_CHECK_POINTER(x) _Generic((x),\
          int: 0,       unsigned int: 0,\
         long: 0,      unsigned long: 0,\
    long long: 0, unsigned long long: 0,\
        float: 0,             double: 0,\
  long double: 0,                       \
      default: 1)

/**
 * Determines whether the variable has likely a pointer type (but may be triggered false-positive)
 */
#define IS_LIKELY_A_POINTER(x) ((sizeof(x) == sizeof(void*)) && __INTERNAL_CHECK_POINTER(x) ? 1 : 0)

演示:

char c = 0;
printf("c is a pointer: %s\n", IS_LIKELY_A_POINTER(c) ? "Yes" : "No");

unsigned long long l = 0;
printf("l is a pointer: %s\n", IS_LIKELY_A_POINTER(l) ? "Yes" : "No");

double d = 0.0;
printf("d is a pointer: %s\n", IS_LIKELY_A_POINTER(d) ? "Yes" : "No");

unsigned char* cp = 0;
printf("cp is a pointer: %s\n", IS_LIKELY_A_POINTER(cp) ? "Yes" : "No");

struct tm* tp = 0;
printf("tp is a pointer: %s\n", IS_LIKELY_A_POINTER(tp) ? "Yes" : "No");

char ia[] = {0, 1, 2, 3, 4, 5, 6, 7};
printf("ia is a pointer: %s\n", IS_LIKELY_A_POINTER(ia) ? "Yes" : "No");

这将输出:

c is a pointer: No
l is a pointer: No
d is a pointer: No
cp is a pointer: Yes
tp is a pointer: Yes
ia is a pointer: Yes // false-positive!

如果您(像我一样)正在寻找一些日志记录(*为特定变量绘制或不绘制 a)并且您不是在寻找防故障结果,试试这个,它可能会有所帮助。干杯!

注意不会在 MSVC 下编译;使用 gcc/clang/等。代替或使用此条件进行自己的后备实现:

#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
    // use _Generic code
#else
    // ¯\_(ツ)_/¯
#endif
于 2019-02-14T21:07:45.400 回答
1

在 Clang 和 GCC 上,如果是具有指针类型的对象,__builtin_classify_type(P)则计算为 5 。P

于 2021-09-29T20:48:22.127 回答
0

有一种方法既没有误报也没有误报,但是如果参数既不是数组也不是指针,编译就会中断。

#define is_same_type(a, b)    __builtin_types_compatible_p(typeof(a), typeof(b))
/* Is a an array? */
#define is_array(a)             (!is_same_type((a), &(a)[0]))
/* Is p a pointer? */
#define is_pointer(p)           (!is_array(p))

它需要 GCC 内置__builtin_types_compatible_p()

行为:

如果 p 是一个数组,它将评估为 0;

否则,如果 p 是指针,它将评估为 1;

否则,编译将中断。

于 2020-04-02T10:54:25.093 回答