3

For the arduino platform, I want to receive 16 bytes and stuff their value inside a structure. Currently I have this code in place

if( Serial.available() >= sizeof( newSection ) ) { // if atleast one full struct is received

    Sections newSection ;                   // declare a local Sections object and fill it
    
    newSection.leftSensor = Serial.read() ;
    newSection.leftSensor = Serial.read() ; // the other variables don't exist yet
    newSection.leftSensor = Serial.read() ;
    newSection.leftSensor = Serial.read() ;
    newSection.leftSensor = Serial.read() ;
    newSection.leftSensor = Serial.read() ;
    newSection.leftSensor = Serial.read() ;
    newSection.leftSensor = Serial.read() ;
    newSection.leftSensor = Serial.read() ;
    newSection.leftSensor = Serial.read() ;
    newSection.leftSensor = Serial.read() ;
    newSection.leftSensor = Serial.read() ;
    newSection.leftSensor = Serial.read() ;
    newSection.leftSensor = Serial.read() ;
    newSection.leftSensor = Serial.read() ;
    newSection.leftSensor = Serial.read() ;
    
    storeLayout( &newSection ) ;
}

The struct 'Sections' does not exist yet but it will contain 16 variables of uint8_t type. Though this will propably work just fine, I prefer to use a for-loop.

if( Serial.available() >= sizeof( newSection ) ) { // if atleast one full struct is received

    Sections newSection ;                   // declare a local sectuin variable and fill it
    
    uint8_t *ptr ;
    ptr = &newSection.leftSensor ;          // let pointer point to the first variable of local struct object < -???
    
    for( byte i = 0 ; i < sizeof( newSection ) ; i ++ ) {
        *ptr = Serial.read() ;
        ptr ++ ;
    }
    
    storeLayout( &newSection ) ;
}

I am not new to pointers, but I have not used this particular example yet and better safe than sorry.

My qeustion: Am I making correct use of the pointer in this example? And if not, how should it look like?

An awnser with just "yes" suffices for me. Thanks in advance.

EDIT: I am aware of structure padding in storage, the struct will be containing precisely 16x uint8_t variables. However it may be a problem that the compiler may re-arrange the storage of the struct's variables in a random order.

Also important thing I perhaps should have mentioned. It is not in the example. But that function storeLayout( &newSection ) will copy the content of this local structure to a structure object which is part of an array.

So there will be an array of 64 of these structures (each containing the 16 uint8_t variables)

Are there ways to use the this example for-loop without having to turn it's variables in an array instead? (to deal the random compiler behaviour for variable storage)

bask185
  • 377
  • 1
  • 3
  • 12
  • 4
    "it will contain 16 variables" Have you heard about arrays? This is the case when you might consider using one. Arrays are designed for this kind of stuff. Don't bother with pointer arithmetic. `newSection.leftSensor[i]= Serial.read();` is all you need. – n. m. could be an AI Oct 20 '20 at 07:09
  • 3
    It isn't clear what your problem is, but `struct Sections { uint8_t leftSensor[16]; };` would allow you to loop over 16 elements. Your first code block is puzzling; you overwrite the same location 16 times, which doesn't seem productive. – Jonathan Leffler Oct 20 '20 at 07:09
  • @JonathanLeffler That was just the exaple sir, OP was trying to show the approach of assigning to individual members. – Sourav Ghosh Oct 20 '20 at 07:10
  • I am fully aware of structure padding. That is why I explicitly mentioned that the struct will contain precisely 16x uint8_t type variables. But as I understand, the compiler might also re-arange the storage of the struct's variables in a random order? – bask185 Oct 20 '20 at 07:12
  • 1
    No; the elements of the structure must be allocated in the order declared, possibly with padding between elements or after the last element, but no padding is allowed before the first element. Rearrangement is not allowed. (See C11 [§6.7.2.1 Structure and union specifiers ¶15](http://port70.net/~nsz/c/c11/n1570.html#6.7.2.1p15) and also ¶17.) – Jonathan Leffler Oct 20 '20 at 07:14
  • 1
    Even without padding and reordering the elements, it is illegal to use pointer arithmetics to point beyond the array where the pointer points to. For this definition, variables that have non-array type count as arrays with 1 element and you are not allowed to use pointer arithmetics beyond 1 element after the last element. – Gerhardh Oct 20 '20 at 07:30
  • People... struct padding doesn't exist on 8 bit systems. An 8 bitter which wouldn't be able to read "misaligned" would be completely broken by definition, since its preferred alignment is 1 byte. And this is why we should tag questions [tag:embedded], before the PC programmers rush in. – Lundin Oct 20 '20 at 07:48
  • Added tags and I learned my lesson, thank you – bask185 Oct 20 '20 at 07:52

1 Answers1

1

i think your path is correct your code it's ok

you can see this answer for sending and receiving Packet

and the following example show how to point to a item of struct

typedef struct {
    uint16_t X;
    uint8_t  Y;
    uint8_t  Z;
} Packet;

Packet mPacket;

uint8_t* pY = &mPacket.Y;
uint16_t* pX = &mPacket.X;

// point to whole struct and cast it to byte array 
uint8_t* pPacketBytes = (uint8_t*) &mPacket;

and if you want ignore padding in structs add the following code

#pragma pack(push, 1)

// define your structs
typedef struct {
    uint16_t X;
    uint8_t  Y;
    uint8_t  Z;
} PacketNoPadding;

#pragma pack(pop)

you can see result with print sizeof(Packet)

  • remember there is no padding in 8bit system such as Arduino UNO or AVR, but padding in ARM MCU is exists
Ali Mirghasemi
  • 462
  • 2
  • 7