简体   繁体   中英

c++ double cast void pointer

So I came across this piece of code reading about arduino's memory

void EEPROM_writeDouble(int address, double value)
{
   byte* p = (byte*)(void*)&value;
   for (int i = 0; i < sizeof(value); i++)
   {
      EEPROM.write(address++, *p++);
   }
}

What intrigues me is this line of code byte* p = (byte*)(void*)&value; do completety but didn't figure it out or maybe. So we have a pointer of type byte(char) that takes the reference of value of type void* and convert it to an byte pointer?

There's no actual reason for this cast. The code is doing type punning and the programmer who wrote the code was probably confused. When trying to get individual bytes out of a variable, you can use an unsigned char* pointer. Which I assume is what byte is in this example. You do not need to go through a void* pointer for this.

Since a conversion from double* to byte* would not be a valid static_cast or const_cast , C++ interprets a C-style cast requesting that conversion as equivalent to a reinterpret_cast . (I'm assuming byte is a typedef for unsigned char or char .)

In the original C++98 Standard and in the C++03 Standard, there were essentially no guarantees on what a reinterpret_cast will do, just saying that the result was "implementation-defined". So a single cast would probably get a pointer to the beginning of the storage for the double variable, but technically you couldn't count on that.

On the other hand, the two conversions in the example, from double* to void* and then from void* to byte* , are valid static_cast conversions, so the C-style casts would both have the behavior of a static_cast . And a static_cast to or from a (non-null) [cv] void* has always guaranteed the void* points at the beginning of the object's storage, resulting in a pointer to an imaginary byte overlapping the storage of the double object. (And reading from an unsigned char or char which is really in storage belonging to an object of a different type is a specific exception to the strict aliasing rules, so that's okay.)

Note that beginning with the C++11 Standard, the behavior of reinterpret_cast , and therefore C-style casts, was more specified for certain categories of pointer conversions: ([expr.reinterpret.cast]/7)

An object pointer can be explicitly converted to an object pointer of a different type. When a prvalue v of type "pointer to T1 " is converted to the type "pointer to cv T2 ", the result is static_cast< cv T2*>(static_cast< cv void*>(v)) if both T1 and T2 are standard-layout types and the alignment requirements of T2 are no stricter than those of T1 , or if either type is void. Converting a prvalue of type "pointer to T1 " to the type "pointer to T2 " (where T1 and T2 are object types and where the alignment requirements of T2 are no stricter than those of T1 ) and back to its original type yields the original pointer value. The result of any other such pointer conversion is unspecified.

So using a recent Standard mode, the two casts are no longer necessary. (The code might have been written earlier, or might need to still work under multiple C++ versions, or might have just been written using old habits. Though using C++-style casts to say what sort of conversion logic you really mean is nearly always a better idea than using C-style casts.)

The standard defines that (byte *)p is the same as (byte *)(void *)p , if p is a pointer.

In more detail, N4659 [expr.reinterpret.cast]/7 defines reinterpret_cast<T1 *>(p) as static_cast<T1 *>(static_cast<void *>(p)) , and [expr.cast] covers that the two C-style casts resolve to static_cast in this case.

So this cast is redundant, we could speculate that the author didn't know the language so well.

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