简体   繁体   中英

How do I safely cast a void* to an int in C?

Or maybe, I shouldn't cast. Here's what I'm doing:

I'm writing a piece of code that links a Linux device driver to a higher level library. The authors of the library use void * (under a new name via typedef ) to store handles to an implementation specific object that describes a communication channel.

The driver I want to connect with the library uses int to store handles to its channels (because they are file descriptors as returned by calls to open() ). So, in my code, I get void * passed in from the library and need to call stuff from the driver using an int and vice versa. 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.
}

The adapters that others have written actually store some struct etc. somewhere and just cast between pointers, so no size issues arise. In my case, I don't really want to manage file descriptors, as the OS already does.

On my PC, I think the pointer is larger than the int , so I could bit-twiddle my way out of this, but the code goes into embedded systems, too, and I'm not experienced enough to make any assumptions about the size of types on those machines.

Edit: Of course you don't need a struct, you can just allocate memory for a plain 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;
}

This assumes there's a matching call to clean up. Something like:

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

Depending on the architecture, you might get away with that. If I understand correctly, the driver never actually uses the void* that you provide to it. It simply stores it to pass it back to your code later on.

Based on that assumption, as long as sizeof(void*) >= sizeof(int), it will be safe to cast between those types because you are sure that it is really a int.

If you cannot guarantee the size condition, or do not want to rely on a hack, you should allocate memory for the int and return the address of that memory. You might use malloc() or allocate a int in a fixed-size array, for example. The downside is that you will need to free that memory when it is no longer needed. I imagine that the driver has some kind of notification that signals your code when the data structure is no longer needed.

Generally on embedded systems, the following CPU models are most common:

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

Generally, the address bus will always be >= than the data bus. I can't think of any CPU where the data bus would be larger than the address bus.

Here's a somewhat dirty trick that may or may not solve the issue:

typedef union
{
  CAN_HANDLE  handle;
  long        value;

} CAN_HANDLE_t;

This should be fairly portable, even though you will likely have to adapt this union to the specific system (far pointers etc).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM