C 如何验证作为void指针传递给函数的值的类型?

C 如何验证作为void指针传递给函数的值的类型?,c,pointers,runtime-error,void-pointers,C,Pointers,Runtime Error,Void Pointers,具有以下代码: 文件:types.h typedef struct Struct_A_T { int A; char B; float C; }Struct_A; 文件:code.c #include "types.h" void Function(const void *const ptr) { Struct_A localStruct = *((Struct_A *)ptr); localStruct.A = 1000; localStru

具有以下代码:


文件:types.h

typedef struct Struct_A_T
{
   int   A;
   char  B;
   float C;
}Struct_A;

文件:code.c

#include "types.h"

void Function(const void *const ptr)
{
   Struct_A localStruct = *((Struct_A *)ptr);

   localStruct.A = 1000;
   localStruct.B = 250;
   localStruct.C = 128.485;
}
#include "types.h"

void Function(const void *const ptr);

int main(void)
{
   Struct_A MyStruct1 = {2, 5, 2.8};
   float local = 24.785;

   /* Correct call */
   Function(&MyStruct1);

   /* Incorrect call!!! */
   Function(&local);
}

文件:main.c

#include "types.h"

void Function(const void *const ptr)
{
   Struct_A localStruct = *((Struct_A *)ptr);

   localStruct.A = 1000;
   localStruct.B = 250;
   localStruct.C = 128.485;
}
#include "types.h"

void Function(const void *const ptr);

int main(void)
{
   Struct_A MyStruct1 = {2, 5, 2.8};
   float local = 24.785;

   /* Correct call */
   Function(&MyStruct1);

   /* Incorrect call!!! */
   Function(&local);
}


并且知道指向void的指针可以用作“通用”指针。如何在“Function”中检测void指针中传递的类型是否正确,以避免文件main.c中最后一次调用引发的运行时错误?

您不能,这是
void*
的主要缺点,您无法确定指向的是什么。你只需要知道。

使用语言功能无法做到这一点。这只能手动完成

一、 首先,在代码的调试构建中使用以下技术

typedef struct Struct_A_T
{
   int   A;
   char  B;
   float C;
#ifdef DEBUG
   unsigned signature; 
#endif /* DEBUG */
}Struct_A;
i、 在调试配置中,我在结构中引入了一个附加字段。该结构类型的每个对象都必须使用特定于该类型的预定义“不可预测”签名值初始化该字段,如

#define STRUCT_A_SIGNATURE 0x12345678
如果所有结构都以某种集中方式创建(如动态分配或由专用函数初始化),那么这很容易做到。如果没有这样的集中位置,这可能会更麻烦。但这是我们有时为安全付出的代价。例如,在你的例子中

Struct_A MyStruct1 = {2, 5, 2.8, 0x12345678 };
顺便说一句,指定的初始值设定项可能会使这种初始化更稳定,更易于阅读

然后,为了将指针从
void*
转换为特定类型,我使用以下cast宏

#ifdef DEBUG
  #define TO_STRUCT_A(p)\
    (assert((p) == NULL || ((Struct_A *)(p))->signature == STRUCT_A_SIGNATURE),\
      (Struct_A *)(p))
#else /* DEBUG */
  #define TO_STRUCT_A(p) ((Struct_A *)(p))
#endif /* DEBUG */
这意味着在
函数中

Struct_A localStruct = *TO_STRUCT_A(ptr);
如果将指向错误类型的指针传递给
函数
,则极有可能触发断言失败

当然,这一切都可以(也应该)使用一组更通用的宏来实现


显然,这只适用于结构类型,您可以向其中注入额外的签名字段。这种方法的另一个潜在问题是,通过在调试版本的结构中引入额外的字段,可能会导致调试和发布版本的行为发生分歧。

您可以使用
sizeof
将结构的大小与
void*
指向的大小进行比较。将指向结构类型的指针传递给
函数
,这不是一个充分但必要的条件。顺便说一句,能够检查变量元数据(包括类型)和更广泛范围的语言属性称为反射。它在许多现代语言中都可以使用,一些位最近已经包含在C++11中,但C仍然缺少它。

eh?如何找到
void*
指向的对象的大小?顺便说一句,指针无法知道它指向的任何对象的大小…
sizeof
不能应用于
void
类型,这意味着它不能应用于未引用的
void*
指针。在任何情况下,VLA上下文之外的
sizeof
是一个纯粹的编译时运算符,因此不可能用于验证任何运行时条件。无效指针和类型安全性是相互排斥的概念。你不能两者兼得,至少在C语言中不能。