【问题标题】:How can I get structure from void* array - C?如何从 void* 数组 - C 中获取结构?
【发布时间】:2014-05-05 15:25:23
【问题描述】:

我正在尝试从作为参数传递给函数的 void* array 检索值。

这是作为void * data 参数传递给我的函数的内容:

void *sredp[3];
sredp[0] = (void*)buf;
sredp[1] = (void*)(&len);
sredp[2] = (void*)(&ri);

来源:https://github.com/kamailio/kamailio/blob/master/udp_server.c#L481

为了解除对前两个字段的引用,我使用以下代码:

int my_fnc(void *data)
{
        str *obuf;
        obuf = (str*)data;
}

str 是 Kamailio 服务器的内部类型 (http://www.asipto.com/pub/kamailio-devel-guide/#c05str)。

我想知道如何从void *data 取消引用ri 字段。我正在尝试这样做:

int my_fnc(void *data)
{
        struct receive_info * ri;
        ri = (struct receive_info*)(data + 2*sizeof(void*));
}

当我尝试打印 receive_info 结构 (https://github.com/sipwise/kamailio/blob/4ee1c6a799713b999aac23de74b26badbe06d0aa/ip_addr.h#L132) 时,它似乎给了我一些数据,但我不知道这些只是内存中的一些随机字节还是我应该检索的正确数据。

所以我的问题是我是否做得对,是否有另一种/更好的方法来实现我的目标?

【问题讨论】:

  • void * 和其他数据指针类型的转换无用且令人困惑,应该删除。
  • 答案取决于您传递给my_fnc 的内容。建议把签名改成void my_fnc(void** data_ptr)
  • 无法在void * 类型上进行指针运算。您可以通过转换为 char * 来指针算术。
  • @harper 我期待将参数传递给我正在监听的事件,就像您在这一行中看到的那样:github.com/kamailio/kamailio/blob/master/udp_server.c#L485 所以它是(void*)
  • @unwind 在这种情况下,这不是选择的问题。我从 Kamailio 服务器的核心获取这个空数组,我无法更改。

标签: c pointers void-pointers


【解决方案1】:

my_fnc 中的data 必须被视为void** 才能提取真实数据。

int my_fnc(void *data)
{
   void** sredp = (void**)data;
   str* obuf = (str*)srdep[0];

   // The pointer that contains len can be obtained from srdep[1]
   // The pointer that contains ri can be obtained from srdep[2]
}

这是一个简单的程序来说明这一点:

#include <stdio.h>

void foo(void* data)
{
   void** realData = (void**)data;
   void* p1 = realData[0];
   void* p2 = realData[1];
   void* p3 = realData[2];

   printf("sredp[0]: %p\n", p1);
   printf("sredp[1]: %p\n", p2);
   printf("sredp[2]: %p\n", p3);

   int a1 = *(int*)p1;
   float a2 = *(float*)p2;
   double a3 = *(double*)p3;

   printf("a1: %d\n", a1);
   printf("a2: %f\n", a2);
   printf("a3: %lf\n", a3);
}

int main()
{
   int a1 = 10;
   float a2 = 20.0f;
   double a3 = 40.0;
   void *sredp[3];
   sredp[0] = &a1;
   sredp[1] = &a2;
   sredp[2] = &a3;

   printf("sredp[0]: %p\n", sredp[0]);
   printf("sredp[1]: %p\n", sredp[1]);
   printf("sredp[2]: %p\n", sredp[2]);

   foo(sredp);
}

运行程序的示例输出:

sredp[0]: 0x28ac2c sredp[1]: 0x28ac28 sredp[2]: 0x28ac20 sredp[0]: 0x28ac2c sredp[1]: 0x28ac28 sredp[2]: 0x28ac20 1:10 a2: 20.000000 a3: 40.000000

【讨论】:

  • 谢谢。您所有的 blue112 和我的解决方案都给了我相同的输出。我不知道正确的输出应该是什么样子,所以我相信你的示例程序,它表明我正在检索的数据应该是正确的数据,而不是内存中的一些随机字节。
  • foo 接受void ** 会减少一层 ick
  • @MattMcNabb foo 是为了模仿 my_fnc。我怀疑my_fnc 是一个回调函数,其签名需要确认回调机制。
【解决方案2】:

您不能在 C 中使用 void* 进行指针运算。它需要使用 sizeof(void),而这实际上并不存在。

问题出在你的函数签名中:

int my_fnc(void *data)

您的指针不是 void*,而是 void**。 所以在使用它之前先投射它:

void** d = (void**) data;
ri = (struct receive_info*)(d + 2);

这将使用 sizeof(void*),它是标准指针大小。

【讨论】:

  • 应该禁止使用void*的指针运算!通常 +1void* 会增加一个字节。你的 D data+2 是指针数据的两个字节。当你假设数据指向一个指针数组时,你会得到第一个指针的第三个和第四个字节与下一个混合。
  • 其实C标准中没有void *的指针运算。
  • @blue112 我试过了,它会生成其他我认为是随机的数据。换句话说,我仍然不确定这些数据是否是我要检索的数据......
  • 编辑了我的答案以考虑您的 cmets。
  • @blue112 当我尝试以我的方式打印并以您的方式打印时,它似乎是一样的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-10-22
  • 2011-10-08
  • 1970-01-01
  • 1970-01-01
  • 2021-04-03
  • 2011-12-29
  • 1970-01-01
相关资源
最近更新 更多