C++: Is it safe to cast pointer to int and later back to pointer again?

前端 未结 12 1789
梦如初夏
梦如初夏 2020-11-28 11:38

Is it safe to cast pointer to int and later back to pointer again?

How about if we know if the pointer is 32 bit long and int is 32 bit long?

long* j         


        
相关标签:
12条回答
  • 2020-11-28 12:37

    Use uintptr_t from "stdint.h" or from "boost/stdint.h". It is guaranteed to have enough storage for a pointer.

    0 讨论(0)
  • 2020-11-28 12:41

    No.

    For instance, on x86-64, a pointer is 64-bit long, but int is only 32-bit long. Casting a pointer to int and back again makes the upper 32-bit of the pointer value lost.

    You may use the intptr_t type in <cstdint> if you want an integer type which is guaranteed to be as long as the pointer. You could safely reinterpret_cast from a pointer to an intptr_t and back.

    0 讨论(0)
  • 2020-11-28 12:41

    No, it is not (always) safe (thus not safe in general). And it is covered by the standard.

    ISO C++ 2003, 5.2.10:

    1. A pointer can be explicitly converted to any integral type large enough to hold it. The mapping function is implementation-defined.
    2. A value of integral type or enumeration type can be explicitly converted to a pointer. A pointer converted to an integer of sufficient size (if any such exists on the implementation) and back to the same pointer type will have its original value; mappings between pointers and integers are otherwise implementation-defined.

    (The above emphases are mine.)

    Therefore, if you know that the sizes are compatible, then the conversion is safe.

    #include <iostream>
    
    // C++03 static_assert.
    #define ASSURE(cond) typedef int ASSURE[(cond) ? 1 : -1]
    
    // Assure that the sizes are compatible.
    ASSURE(sizeof (int) >= sizeof (char*));
    
    int main() {
        char c = 'A';
        char *p = &c;
        // If this program compiles, it is well formed.
        int i = reinterpret_cast<int>(p);
        p = reinterpret_cast<char*>(i);
        std::cout << *p << std::endl;
    }
    
    0 讨论(0)
  • 2020-11-28 12:41

    To an int ? not always if you are on a 64 bit machine then int is only 4 bytes, however pointers are 8 bytes long and thus you would end up with a different pointer when you cast it back from int.

    There are however ways to get around this. You can simply use an 8 byte long data type ,which would work whether or not you are on 32/64 bit system, such as unsigned long long unsigned because you don't want sign extension on 32-bit systems.

    It is important to note that on Linux unsigned long will always be pointer size* so if you are targeting Linux systems you could just use that.

    *According to cppreference and also tested it myself but not on all Linux and Linux like systems

    0 讨论(0)
  • 2020-11-28 12:42

    Is it safe? Not really.

    In most circumstances, will it work? Yes

    Certainly if an int is too small to hold the full pointer value and truncates, you won't get your original pointer back (hopefully your compiler will warn you about this case, with GCC truncating conversions from pointer to integers are hard errors). A long, or uintptr_t if your library supports it, may be better choices.

    Even if your integer type and pointer types are the same size, it will not necessarily work depending on your application runtime. In particular, if you're using a garbage collector in your program it might easily decide that the pointer is no longer outstanding, and when you later cast your integer back to a pointer and try to dereference it, you'll find out the object was already reaped.

    0 讨论(0)
  • 2020-11-28 12:42

    If your going to be doing any system portable casting, you need to use something like Microsofts INT_PTR/UINT_PTR, the safety after that relies on the target platforms and what you intend doing to the INT_PTR. generally for most arithmatic char* or uint_8* works better while being typesafe(ish)

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