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


10

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

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

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


10
你不能!至少,您将需要在函数中添加第二个参数,以指示要void*指向的内容。
阿德里安·摩尔

4
...并且如果仍然要添加第二个参数,则可以编写两个单独的函数func_strfunc_struct在编译时进行类型检查。
M Oehm '19

是的,这就是为什么我在考虑是否仅在一种功能中可能的原因
localhost,

1
您不能以安全和便携式的方式。如果您足够勇敢,则可以尝试使用启发式方法来尝试猜测内存的第一个字节是否看起来像您期望的字符,但是我不认为这是安全的
Serge Ballesta,

如果只想为字符串和结构函数提供通用名称,则可以使用_Generic宏。您还可以创建自我识别类型,例如使用带标记的unions,这意味着您不能传递原始char *字符串。所有这些可能都比它的价值还要麻烦。
M Oehm

Answers:


12

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

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

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


此外,编译器实际上知道所指向的数据类型。因此,如果您跳入某个void*函数,转换为错误的类型,然后取消引用数据...,则将调用所有方式的未定义行为。
隆丁

5

void*泛型编程已被弃用,如今在很多情况下都不应该使用它们。它们很危险,因为它们会导致不存在类型安全性。正如您指出的那样,您还会丢失类型信息,这意味着您必须将一些麻烦的内容enum与一起拖曳void*

相反,您应该使用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); 
}

请记住提供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) 

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.