struct arrays and reading struct like an array.

I am fixing some old code:

struct {
  uint8_t startbyte;
  uint8_t sensor;
  uint8_t alarm;
  uint8_t endbyte;
  uint8_t chksum;
}
TextModule;

then , later on, the array is copied using:

memcpy(&outBuffer, &TextModule, PacketSize);

What is the difference between

struct {
  uint8_t startbyte;
...}
TextModule;

and

struct TextModule{
  uint8_t startbyte;
...};

At least, the memcpy does not work with the later example.

finally, after memcpy, those bytes are read out one by one from the array, .. could that be done right from the struct ? (reading it out like an array, no memcpy ? )

At least, the memcpy does not work with the later example.

Doesn't work,or doesn't compile?

AndreK:
What is the difference between

struct {

uint8_t startbyte;
...}
TextModule;




and



struct TextModule{
  uint8_t startbyte;
...};




At least, the memcpy does not work with the later example.

The first one is a definition, while the second one is a declaration. The first one reserves 5 bytes of memory, and stores a reference in the variable "TextModule". The second example only introduces the type "TextModule" to the compiler. No memory is reserved, but you can create variables of type "TextModule" like so:

struct TextModule modules;

AndreK:
finally, after memcpy, those bytes are read out one by one from the array, .. could that be done right from the struct ? (reading it out like an array, no memcpy ? )

I think you need to do a bit more explaining here (post the full code). Do you really have an array of structs? What do you mean by "[...] those bytes are read out one by one from the array [...]"?
What is the purpose of the mem copy? We don't know your architecture and you haven't shown any code.

AndreK:
finally, after memcpy, those bytes are read out one by one from the array, .. could that be done right from the struct ? (reading it out like an array, no memcpy ? )

Yes. Declare a pointer to uint8_t, point it at the structure and use the pointer just as you did the array. Be aware that there may be packing issues to account for.

AndreK:
I am fixing some old code:

struct {

uint8_t startbyte;
 uint8_t sensor;
 uint8_t alarm;
 uint8_t endbyte;
 uint8_t chksum;
}
TextModule;




then , later on, the array is copied using:


memcpy(&outBuffer, &TextModule, PacketSize);





What is the difference between 


struct {
 uint8_t startbyte;
…}
TextModule;




and



struct TextModule{
 uint8_t startbyte;
…};

In the former, the optional structure tag (the structure name after the “struct” declaration) is absent but the structure variable (TextModule) is present. TextModule is basically a variable of a type defined by that struct.

In the latter, you’ve got a structure tag but no variable. The structure exists only logically, not in a way that could be addressed. For that you’d need:

struct TextModuleStruct {
  uint8_t startbyte;
  uint8_t sensor;
  uint8_t alarm;
  uint8_t endbyte;
  uint8_t chksum;
};

TextModuleStruct TextModule;

finally, after memcpy, those bytes are read out one by one from the array, … could that be done right from the struct ? (reading it out like an array, no memcpy ? )

Seems like it:

struct TextModuleStruct {
  uint8_t   startbyte;
  uint8_t   sensor;
  uint8_t   alarm;
  uint8_t   endbyte;
  uint8_t   chksum;
  int       lastguy;
};

TextModuleStruct TextModule;

void setup() 
{
    Serial.begin(9600);
    
    TextModule.startbyte = 0x01;
    TextModule.sensor = 0x02;
    TextModule.alarm = 0x03;
    TextModule.endbyte = 0x04;
    TextModule.chksum = 0x05;
    TextModule.lastguy = 0x5a5a;
}

void loop() 
{
    byte *vPtr;

    vPtr = (byte *)&TextModule;

    for( int i=0; i<sizeof( TextModuleStruct ); i++ )
        Serial.println( *(vPtr+i) );
        
    Serial.println();
    delay(100);
    
}

memcpy() seems like a cleaner way to do it.

Thanks all.
@AWOL - does not compile it would fail at memcpy , (apparently does not like declaration as pointer)

I did not share the code as it's an unholy big 2560 sketch with 8 pages, timer driven, some thousand lines, and depends on very special hardware to provide the data that eventually populates, and later on , on request, is sent over serial.

The real reason I am asking and fooling around with it, is that I am moving it to a STM32103.
Those struct's are really much bigger. and contain uint8,16,32 as well as char too.
After much ttroubleshooting, I see that data from a perfectly valid and perfectly populated struct, suddenly gets another byte in the middle, not understanding where it comes from. (suspecting memcpy?)

example; I set struct byte55 to 0xAA , byte56 to 0xBB , yet, after memcpy of them all to an array, and then reading one after another, at some point (after 55 bytes) , byte55 is AA, 56 is 0x0 , 57 is BB(which should be in position 56), 58 is another strange byte ...

first found the problem using logic/protocol analyser when things would not work, now I see it clearly when programmed as debug output.

This is because the STM32 is a 32-bit architecture and the compiler will add padding bytes if you don't explicitly tell it not to (struct packing).

Padding is added, to allow aligned memory accesses to the structure members. Take this example:

struct
{
    uint8_t byte1;
    uint8_t byte2;
    uint8_t byte3;
    uint32_t number;
}

Without padding, accessing the 'number' struct member would require two memory accesses. The first memory access would get 4 bytes: byte1, byte2, byte3, MSB of number. The second memory access would give the last 3 bytes of 'number'. With padding 'number' can be read in one access.

struct
{
    uint8_t byte1;
    uint8_t byte2;
    uint8_t byte3;
    uint8_t paddedByte;
    uint32_t number;
}

For larger structures it is important to pack the members together:

struct
{
    uint8_t byte1;
    uint8_t byte2;
    uint8_t byte3;
    uint32_t number;
    char character;
}

Will be compiled to

struct
{
    uint8_t byte1;
    uint8_t byte2;
    uint8_t byte3;
    uint8_t padding1;
    uint32_t number;
    char character;
    uint8_t padding2;
    uint8_t padding3;
    uint8_t padding4;
}

Whereas

struct
{
    uint8_t byte1;
    uint8_t byte2;
    uint8_t byte3;
    char character;
    uint32_t number;
}

Doesn't need padding at all (assuming char is 8-bits wide).

@LightuC
Thank you, you identified, and solved my issue perfectly. This explains everything :slight_smile: