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



我正在编写一个函数,我想接受 2type秒的参数。

  • string(字符 *(
  • 将有 n 个元素的structure

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

void*的翻译是
"亲爱的编译器,这是一个指针,没有其他信息给你。

通常编译器比你(程序员(更了解,因为他之前得到的信息仍然记得,你可能已经忘记了。
但在这种特殊情况下,你知道得更好或需要知道得更好。在所有void*情况下,信息都是以其他方式获得的,但仅限于"碰巧知道"的程序员。因此,程序员必须向编译器提供信息 - 或者更好地提供给正在运行的程序,因为void*具有的一个优点是信息可以在运行时更改。
通常,这是通过附加参数向函数提供信息来完成的,有时是通过上下文,即程序"碰巧知道"(例如,对于每种可能的类型都有一个单独的函数,无论哪个函数被调用都意味着该类型(。

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

void*

对于泛型编程来说有点不推荐使用,现在你应该使用它们的情况并不多。它们是危险的,因为它们会导致不存在的类型安全性。正如您所指出的,您还会丢失类型信息,这意味着您必须随void*一起拖动一些繁琐enum

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

#include <stdio.h>
typedef struct
{
int n;
} s_t; // some struct
void func_str (const char* str)
{
printf("Doing string stuff: %sn", str);
}
void func_s (const s_t* s)
{
printf("Doing struct stuff: %dn", 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"

我建议你用这样的东西来包装你的参数:

#include <stdio.h>
struct WrappedArg{
int Type;
void* Pointer;
};
typedef struct WrappedArg WrappedArg;

struct Other_Structure{
int x, y, z;
};
typedef struct Other_Structure Other_Structure;

void Our_Function(void* data){
WrappedArg* translated_data = (WrappedArg*) data;
if(translated_data->Type == 0){
// print srting, if string passed
printf("You passed string: %sn", (char*) translated_data->Pointer);

} else {
// recreate structure_data from pointer
Other_Structure* structure_data = (Other_Structure*)translated_data->Pointer;
printf("You passed sructure with x, y, z: %d, %d, %dn",
structure_data->x, structure_data->y, structure_data->z);

}
}

int main(){
Other_Structure structure_data = {1,2,3};
char* string_data = "Hi there!";
WrappedArg arguments = {
0, // type
string_data
};
Our_Function((void*)&arguments);
// OR
arguments.Type = 1;
arguments.Pointer = &structure_data;
Our_Function((void*)&arguments);
return 0;
}

最新更新