Casting a pointer and then dereferencing it

I am having trouble casting the pointer to a single-byte type to a larger type then dereferencing it (so that my data can be interpreted as a larger data type). The code seems to hang or get stuck when it hits/executes that line (my print statements, as well as the rest of my program, seem to halt right at that point.) Here's what my code looks like:

  byte* sBuf = (byte*)getSendBuf();
  
  if( sBuf != 0){
        Serial.println(sBuf[0], HEX);
        Serial.println(sBuf[1], HEX);
        Serial.println(sBuf[2], HEX);
        Serial.println(sBuf[3], HEX);
        Serial.println((long)sBuf[0],DEC);

        long val = *((long*)sBuf); // THIS LINE
        Serial.println(val);

The line marked "THIS LINE" is the one where my execution seems to stop. If I try other forms of de-referencing the data (e.g [0]), the code behaves the same, but when I set it to a constant value, it works fine.

getSendBuf returns a char pointer, and the code behaves the same without the byte cast in the beginning.

Does your getSendBuf() return a heap or stack pointer? If you are unsure, post the code of it.

It returns a pointer to a global object/array (so I think technically neither?)

char* to_return = global_ptr;
        Serial.print("to return ");Serial.println(((int*)to_return)[0]);

This behaves the same way. The last thing I see in the Serial Monitor before everything halts is "to return"

Put a Serial.flush() after the Serial.print to make sure that is where execution stops, otherwise the serial output will seriously lag behind the code.

walaaa:

char* to_return = global_ptr;

Serial.print("to return ");Serial.println(((int*)to_return)[0]);




This behaves the same way. The last thing I see in the Serial Monitor before everything halts is "to return"

Post the whole program

I just tried that and the code behaves the same. It also behaves the same if I do the cast on the pointer assignment line, instead of the Serial.print line.

Also, every time this happens, I have to hard-reset the Arduino before I can upload new code.

Try printing the value of the pointer itself, say Serial.println((long)ptr, HEX);

It is appropriately aligned for the data type you are casting to? What are the alignment requirements for your platform?

On many platforms, up to some small power of two, to read a value of size n, the pointer must be aligned to an address that is a multiple of n, i.e. to read a long the pointer may have to be a multiple of four.

To guarantee alignment, you can use a union.

It does not appear anyone has yet pointed out the OP is trying to generate a pointer from the four byte variable sByte, but pointers in most Arduinos are only two bytes....

A WHOLE lot more information is needed....

Regards,
Ray L.

RayLivingston:
It does not appear anyone has yet pointed out the OP is trying to generate a pointer from the four byte variable sByte, but pointers in most Arduinos are only two bytes…

A WHOLE lot more information is needed…

Regards,
Ray L.

In this context, it doesn’t matter if a pointer is 4 bytes or 2 bytes.

arduino_new:
In this context, it doesn't matter if a pointer is 4 bytes or 2 bytes.

It could make a BIG difference how it was STORED as a 4-byte quantity, which we don't know. We don't even know what TYPE it is, much less how it was initialized....

Regards,
Ray L.

OP has not yet chosen to share the full code or even the board type. On 32-bit ARM and ESP-based boards, pointers are 4 bytes.

And, as has been discussed many times here, dereferencing a type-punned pointer is frowned upon or even forbidden by the C++ compiler (depending on options flags, I imagine).

I am using a MKR WiFi1010 Arduino board. The full code is about ~1000 lines and the vast majority of it is irrelevant.

I am casting the pointer to another type of pointer- so all pointers in the system should be the same size, regardless of what they point to, right?

walaaa:
The full code is about ~1000 lines and the vast majority of it is irrelevant.

And nobody wants to look at 1000 lines of irrelevant clutter. That's why you should make a Minimal Reproducible Example (MRE).

But, again what you are trying to do is against C++ best practices. As it's not guaranteed to work by the language standard.

My experience has mostly been with C, which this type of pointer manipulation seems to work fine. I didn't realize C++ was different when it came to pointer handling. Do you happen to know why?

Google search for 'ereferencing a type-punned pointer'.

walaaa:
My experience has mostly been with C, which this type of pointer manipulation seems to work fine. I didn’t realize C++ was different when it came to pointer handling. Do you happen to know why?

The short version is this paragraph from the C++ standard:

Many compilers issue “strict aliasing” warnings in such cases, even though technically such constructs run afoul of something other than the paragraph commonly known as the “strict aliasing rule”.

The purpose of strict aliasing and related rules is to enable type-based alias analysis, which would be decimated if a program can validly create a situation where two pointers to unrelated types (e.g., an int* and a float*) could simultaneously exist and both can be used to load or store the same memory (see this email on SG12 reflector). Thus, any technique that is seemingly capable of creating such a situation necessarily invokes undefined behavior.

When it is needed to interpret the bytes of an object as a value of a different type, std::memcpy or std::bit_cast (since C++20)can be used:

The recommended way of doing these kinds of type conversions is to have an object of the type you want, and use memcpy() to copy the bits into it. This trivially ensures that the two objects do not refer to the same memory.

https://en.cppreference.com/w/cpp/language/reinterpret_cast#Type_aliasing