如何验证void指针(void *)是否为两种数据类型之一?

loc*_*ost 9 c gcc types clang

我正在编写一个要接受2 types参数的函数。

  • A string(字符*)
  • 一个structure将有n个元素的地方。

为了实现这一点,我正在考虑使用简单void *的参数类型。但是我不知道如何安全地验证参数是否是一种类型。

Yun*_*sch 9

的翻译void*
“亲爱的编译器,这是一个指针,对此您没有其他信息。”。

通常,编译器比您(程序员)更了解您,因为他获取的信息更早并且仍然记得并且您可能已经忘记了。
但是在这种特殊情况下,您会了解更多或需要了解更多。在所有情况下,void*信息都是可用的,但仅适用于“偶然知道”的程序员。为此,程序员必须将信息提供给编译器-或者更好地提供给正在运行的程序,因为一个优点void*是该信息可以在运行时更改。
通常,这是通过通过附加的参数给函数(有时是通过上下文)将信息提供给程序来完成的,例如,程序“碰巧知道”(例如,对于每种可能的类型,都有一个单独的函数,无论调用哪个函数都暗含该类型)。

所以最后void*不包含类型信息。
许多程序员误解为“我不需要知道类型信息”。
但是事实恰恰相反,使用void* 增加程序员的责任,以跟踪类型信息并将其适当地提供给程序/编译器。


Lun*_*din 5

void*对于泛型编程有点不推荐,现在应该使用它们的情况并不多。它们很危险,因为它们导致不存在的类型安全。正如您所指出的,您还会丢失类型信息,这意味着您必须enumvoid*.

相反,您应该使用 C11 _Generic,它可以在编译时检查类型并添加类型安全。例子:

#include <stdio.h>

typedef struct
{
  int n;
} s_t; // some struct

void func_str (const char* str)
{
  printf("Doing string stuff: %s\n", str);
}

void func_s (const s_t* s)
{
  printf("Doing struct stuff: %d\n", s->n);
}

#define func(x) _Generic((x),              \
  char*: func_str, const char*: func_str,  \
  s_t*:  func_s,   const s_t*:  func_s)(x) \


int main()
{
  char str[] = "I'm a string";
  s_t s = { .n = 123 };

  func(str);
  func(&s); 
}
Run Code Online (Sandbox Code Playgroud)

请记住提供const您希望支持的所有类型的合格 ( ) 版本。


如果在调用者传递错误类型时想要更好的编译器错误,可以添加静态断言:

#define type_check(x) _Static_assert(_Generic((x), \
  char*:   1,  const char*: 1,  \
  s_t*:    1,  const s_t*:  1,  \
  default: 0), #x": incorrect type.")

#define func(x) do{ type_check(x); _Generic((x),     \
  char*: func_str, const char*: func_str,            \
  s_t*:  func_s,   const s_t*:  func_s)(x); }while(0) 
Run Code Online (Sandbox Code Playgroud)

如果您尝试类似的操作,int x; func(x);您将收到编译器消息"x: incorrect type"