When is an integer<->pointer cast actually correct?

后端 未结 15 2616
北荒
北荒 2020-12-13 07:48

The common folklore says that:

  • The type system exists for a reason. Integers and pointers are distinct types, casting between them is a malpractice in the m

相关标签:
15条回答
  • 2020-12-13 08:36

    I've used such systems when I'm trying to walk byte-by-byte through an array. Often times, the pointer will walk multiple bytes at a time, which causes problems that are very difficult to diagnose.

    For example, int pointers:

    int* my_pointer;
    

    moving my_pointer++ will result in advancing 4 bytes (in a standard 32-bit system). However, moving ((int)my_pointer)++ will advance it one byte.

    It's really the only way to accomplish it, other than casting your pointer to a (char*). ((char*)my_pointer)++

    Admittedly, the (char*) is my usual method since it makes more sense.

    0 讨论(0)
  • 2020-12-13 08:41

    The only time i cast a pointer to an integer is when i want to store a pointer, but the only storage i have available is an integer.

    0 讨论(0)
  • 2020-12-13 08:42

    There is an old and good tradition to use pointer to an object as a typeless handle. For instance, some people use it for implementing interaction between two C++ units with flat C-style API. In that case, handle type is defined as one of integer types and any method have to convert a pointer into an integer before it can be transfered to another method that expects an abstract typeless handle as one of its parameter. In addition, sometimes there is no other way to break up a circular dependency.

    0 讨论(0)
  • 2020-12-13 08:46

    When is it correct to store pointers in ints? It's correct when you treat it as what it is: The use of a platform or compiler specific behavior.

    The problem is only when you have platform/compiler specific code littered throughout your application and you have to port your code to another platform, because you've made assumptions that don't hold true any longer. By isolating that code and hiding it behind an interface that makes no assumptions about the underlying platform, you eliminate the problem.

    So as long as you document the implementation, separate it behind a platform independent interface using handles or something that doesn't depend on how it works behind the scenes, and then make the code compile conditionally only on platforms/compilers where it's been tested and works, then there's no reason for you not to use any sort of voodoo magic you come across. You can even include large chunks of assembly language, proprietary API calls, and kernel system calls if you want.

    That said, if your "portable" interface uses integer handles, integers are the same size as pointers on the implementation for a certain platform, and that implementation uses pointers internally, why not simply use the pointers as integer handles? A simple cast to an integer makes sense in that case, because you cut out the necessity of a handle/pointer lookup table of some sort.

    0 讨论(0)
  • 2020-12-13 08:48

    One example is in Windows, e.g. the SendMessage() and PostMessage() functions. They take a HWnd (a handle to a window), a message (an integral type), and two parameters for the message, a WPARAM and an LPARAM. Both parameter types are integral, but sometimes you must pass pointers, depending on the message you send. Then you will have to cast a pointer to an LPARAM or WPARAM.

    I would generally avoid it like the plague. If you need to store a pointer, use a pointer type, if that is possible.

    0 讨论(0)
  • 2020-12-13 08:51

    The most useful case in my mind is the one that actually has the potential to make programs much more efficient: a number of standard and common library interfaces take a single void * argument which they will pass back to a callback function of some sort. Suppose your callback doesn't need any large amount of data, just a single integer argument.

    If the callback will happen before the function returns, you can simply pass the address of a local (automatic) int variable, and all is well. But the best real-world example for this situation is pthread_create, where the "callback" runs in parallel and you have no guarantee that it will be able to read the argument through the pointer before pthread_create returns. In this situation, you have 3 options:

    1. malloc a single int and have the new thread read and free it.
    2. Pass a pointer to a caller-local struct containing the int and a synchronization object (e.g. a semaphore or a barrier) and have the caller wait on it after calling pthread_create.
    3. Cast the int to void * and pass it by value.

    Option 3 is immensely more efficient than either of the other choices, both of which involve an extra synchronization step (for option 1, the synchronization is in malloc/free, and will almost certainly involve some cost since the allocating and freeing thread are not the same).

    0 讨论(0)
提交回复
热议问题