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

后端 未结 15 2615
北荒
北荒 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:51

    It's very common in embedded systems to access memory-mapped hardware devices where the registers are at fixed addresses in the memory map. I often model hardware differently in C vs. C++ (with C++ you can take advantage of classes and templates), but the general idea can be used for both.

    A quick example: suppose you have a timer peripheral in hardware, and it has 2 32-bit registers:

    • a free-running "tick count" register, which decrements at a fixed rate (e.g. every microsecond)

    • a control register, which allows you to start the timer, stop the timer, enable a timer interrupt when we decrement the count to zero, etc.

    (Note that a real timer peripheral is usually significantly more complicated).

    Each of these registers are 32-bit values, and the "base address" of the timer peripheral is 0xFFFF.0000. You could model the hardware as follows:

    // Treat these HW regs as volatile
    typedef uint32_t volatile hw_reg;
    
    // C friendly, hence the typedef
    typedef struct
    {
      hw_reg TimerCount;
      hw_reg TimerControl;
    } TIMER;
    
    // Cast the integer 0xFFFF0000 as being the base address of a timer peripheral.
    #define Timer1 ((TIMER *)0xFFFF0000)
    
    // Read the current timer tick value.
    // e.g. read the 32-bit value @ 0xFFFF.0000
    uint32_t CurrentTicks = Timer1->TimerCount;
    
    // Stop / reset the timer.
    // e.g. write the value 0 to the 32-bit location @ 0xFFFF.0004
    Timer1->TimerControl = 0;
    

    There are 100 variations on this approach, the pros and cons of which can be debated forever, but the point here is only to illustrate a common use of casting an integer to a pointer. Note that this code isn't portable, is tied to a specific device, assumes the memory region is not off-limits, etc.

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

    It is never useful to perform such casts, unless you have full knowledge of the behaviour of your compiler+platform combination, and wish to exploit it (your question scenario is one such example).

    The reason I say it is never useful is because in general, you don't have control of the compiler, nor full knowledge of what optimisations it may choose to do. Or to put it another way, you aren't able to precisely control the machine code it will generate. So in general, you can't implement this sort of trick safely.

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

    I have one use for such a thing in network wide ID's of objects. Such a ID would combine identifications of machine (e.g IP address), process id and the address of the object. To be sent over a socket the pointer part of such an ID must be put into a wide enough integer such that it survives transport back and forth. The pointer part is only interpreted as a pointer (= cast back to a pointer) in the context where this makes sense (same machine, same process), on other machines or in other processes it just serves to distinguish different objects.

    The things one needs to have that working is the existence uintptr_t and uint64_t as a fix width integer type. (Well only works on machines that have at most 64 addresses :)

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