Home > Software engineering >  unexpected address for a referenced indirected pointer in a struct as opposed to same declaration wi
unexpected address for a referenced indirected pointer in a struct as opposed to same declaration wi

Time:03-26

I have a struct containing a byte array and several typecast references to various points in the array. Bytes 4:7 may be interpreted as a float, int32_t, or uint32_t as determined by other fields in the packet being received over a serial connection. To make access simple (e.g. message.argument.F for a float interpretation), I made multiple references to indirected typecast pointers. But when I ran the program, I got a segfault trying to write to the references in the struct. As near as I can tell, the problem has to do with the container, as illustrated by this example snippet (cpp shell: http://cpp.sh/3vmoy):

#include <iostream>
#include <cstring>
using namespace std;

#define PACKET_SIZE 9
#define ARG_I 4

struct Message{
  uint8_t bytes[PACKET_SIZE];
  uint8_t* argbytes = static_cast<uint8_t*>(argp);
  float& argf = *static_cast<float*>(argp);
  void* argp = &bytes[ARG_I];
} message;



int main(){
    // USING STRUCT    
    cout << "Using message struct" << endl;
    cout << message.argp << endl;                           // the pointer at index stored in struct
    cout << static_cast<float*>(message.argp) << endl;      // casting the pointer to a float* - should be the same
    cout << &message.argf << endl;                          // the address of the float reference cast from argp, ** should be the same BUT IS NOT **
    
    // RAW VARS
    uint8_t bytes[PACKET_SIZE];
    void* argp = &bytes[ARG_I];
    float& argf = *static_cast<float*>(argp);

    cout << endl << "using raw vars" << endl;
    cout << argp << endl;                                   // a pointer to a byte in an array of bytes.
    cout << static_cast<float*>(argp) << endl;              // the same pointer cast as a float*
    cout << &argf << endl;                                  // the address of a float reference cast from argp, **should be the same AND IS.**
}

I expect to see the same address for the pointer, a typecast pointer, and the address of the reference for the indirected pointer. I do see that if I create an array and the pointer/reference as standalone variables, but not for the same declarations in a struct. What arcane knowledge do I lack to explain this behavior (or what silly thing have I overlooked?)

My thoughts for fixing this are to a) ignore it and just typecast the pointer as necessary instead, or b) make some setter/getter functions to access the argument portion of the serial "packet".

CodePudding user response:

There are two major, fundamental differences between the two alternative chunks of code.

    void* argp = &bytes[ARG_I];
    float& argf = *static_cast<float*>(argp);

Here, this constructs and initializes argp first, then argf.

  float& argf = *static_cast<float*>(argp);
  void* argp = &bytes[ARG_I];

And here, it does not.

This initializes argf first, then argp. The consequences of this should be quite apparent.

Note: I'm ignoring all the aliasing rule violations here, that are likely to be a source of further undefined behavior.

  • Related