如何安全地将void *转换为C中的int?

时间:2011-02-07 15:43:20

标签: c pointers casting

或许,我不应该施展。这就是我正在做的事情:

我正在编写一段代码,将Linux设备驱动程序链接到更高级别的库。该库的作者使用void *(通过typedef的新名称)将句柄存储到描述通信通道的特定于实现的对象。

我想与库连接的驱动程序使用int来存储其通道的句柄(因为它们是调用open()返回的文件描述符)。所以,在我的代码中,我从库中传入void *,需要使用int从驱动程序调用内容,反之亦然。 I. e。:

// somewhere in the library ...
typedef void* CAN_HANDLE;

// ... in my code
CAN_HANDLE canOpen_driver(s_BOARD *board)
{
  int fd;
  // ...
  fd = open(busname, O_RDWR);
  // ...
  return (CAN_HANDLE) fd; // <-- not safe, especially not when converting back.
}

其他人编写的适配器实际上存储了一些结构等等,只是在指针之间进行转换,因此不会出现大小问题。在我的情况下,我真的不想像操作系统那样管理文件描述符。

在我的电脑上,我认为指针大于int,所以我可以用它来解决这个问题,但代码也会进入嵌入式系统,而且我没有足够的经验对这些机器上的类型大小做出任何假设。

3 个答案:

答案 0 :(得分:3)

编辑:当然你不需要一个结构,你可以只为普通的int分配内存。

CAN_HANDLE canOpen_driver(s_BOARD *board)
{
  int *fd = malloc(sizeof(int));
  if (fd)
  {
    // ...
    *fd = open(busname, O_RDWR);
    // ...
    return (CAN_HANDLE) fd;
  } 

  // failure
  return NULL;
}

这假设有一个匹配的清理呼叫。类似的东西:

void canClose_driver(CAN_HANDLE handle)
{
  int *fd = handle;
  free(fd);
}

答案 1 :(得分:2)

根据架构,您可能会侥幸逃脱。如果我理解正确,驱动程序实际上从未使用您提供给它的void *。它只是存储它以便稍后将其传递回您的代码。

基于这个假设,只要sizeof(void *)&gt; = sizeof(int),就可以安全地在这些类型之间进行转换,因为你确定它实际上是一个int。

如果你不能保证大小条件,或者不想依赖hack,你应该为int分配内存并返回该内存的地址。例如,您可以使用malloc()或在固定大小的数组中分配int。缺点是,当不再需要时,您将需要释放该内存。我想,当不再需要数据结构时,驱动程序会发出某种通知,告知您的代码。

答案 2 :(得分:0)

通常在嵌入式系统上,以下CPU型号最常见:

Data bus   Address bus   

 8 bit     16 bit  
 8 bit     16+8 bit (banking) 
16 bit     16 bit 
16 bit     16+8 bit (banking) 
32 bit     32 bit

通常,地址总线将始终> =数据总线。我想不出任何数据总线大于地址总线的CPU。

这是一个有点肮脏的技巧,可能会或可能不会解决问题:

typedef union
{
  CAN_HANDLE  handle;
  long        value;

} CAN_HANDLE_t;

这应该是相当便携的,即使你可能必须使这个联盟适应特定的系统(远指针等)。