There have been many discussions here about the pointer and union shenanigans people attempt to subvert C++'s type system and the resultant risk of undefined behavior.
My understanding is that the one exception that is permitted is to cast a pointer to variable (or array, or struct, etc) to a 'char *' (or 'uint8_t *', etc). You may then read the original variable's bytes using this pointer.
For example (since the LoRaClass class inherits from Stream), you can legal do:
uint32_t dataToSend;
dataToSend = getSomeData();
LoRa.write(reinterpret_cast<const uint8_t*>(dataToSend), sizeof(dataToSend));
Looking at the Print class's implementation of write() you can see how it reads the data using a 'const uint8_t *':
size_t Print::write(const uint8_t *buffer, size_t size)
{
size_t n = 0;
while (size--) {
if (write(*buffer++)) n++;
else break;
}
return n;
}
So, finally the question that @J-M-L and I were were debating in a different thread … is it also legal to write into a variable byte-by-byte or must you explicitly use memcpy()? Again with the LoRa example, can you legally do:
uint32_t receivedData;
LoRa.readBytes(reinterpret_cast<uint8_t*>(receivedData), sizeof(receivedData));
Looking at the code for readBytes(), you can see that it puts data into the variable byte-by-byte:
size_t Stream::readBytes(char *buffer, size_t length)
{
size_t count = 0;
while (count < length) {
int c = timedRead();
if (c < 0) break;
*buffer++ = (char)c;
count++;
}
return count;
}
memcpy() also uses the byte-by-byte technique. So is it OK or must the compiler explicitly see the function memcpy() being called? If that latter, it sure seems to be an inconsistent asymmetry. It also means I couldn't write my own function myMemCpy() that uses the EXACT SAME source code as memcpy() just with a different name. That blows my mind.
I know that @PieterP has written on this extensively. Perhaps he has an answer.