指向结构体内部元素的指针(C语言)

3
对于Arduino平台,我想接收16个字节并将它们的值存入一个结构中。目前我已经有了以下代码。
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 ) ;
}

结构体“Sections”尚不存在,但它将包含16个uint8_t类型的变量。虽然这可能完全可行,但我更喜欢使用for循环。

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 ) ;
}

我对指针不陌生,但我还没有使用过这个特定的例子,安全起见最好确认一下。

我的问题是:我在这个例子中使用指针是否正确? 如果不正确,应该怎么做?

仅回答“是”即可。

编辑: 我知道结构体填充存储的情况,该结构体将恰好包含16个uint8_t变量。 然而,编译器可能会以随机顺序重新排列结构体变量的存储。

另一个重要的事情,也许我应该提一下。它不在示例中。 但是,函数storeLayout(&newSection)将把此本地结构的内容复制到作为数组一部分的结构对象中。
因此,将有一个由64个这些结构组成的数组(每个结构包含16个uint8_t变量)。
有没有办法在不将其变量转换为数组的情况下使用此示例for循环? (以处理变量存储的随机编译器行为)


4
“它将包含16个变量。” 你听说过数组吗?在这种情况下,你可能会考虑使用它。数组是为这种类型的内容设计的。不必纠结于指针算术。newSection.leftSensor[i]= Serial.read(); 是你需要的全部。 - n. m.
3
你的问题不是很清楚,但 struct Sections { uint8_t leftSensor[16]; }; 可以让你遍历 16 个元素。你的第一个代码块令人困惑,因为你会重复写入相同的位置 16 次,这似乎没有什么意义。 - Jonathan Leffler
我完全了解结构体填充。这就是为什么我明确提到该结构体将包含精确的16个uint8_t类型变量。但是据我所知,编译器也可能以随机顺序重新排列结构体变量的存储方式? - bask185
1
不可以;结构体的元素必须按照声明的顺序分配,可能在元素之间或最后一个元素之后填充,但是不允许在第一个元素之前填充。不允许重新排列。 (请参见C11 [§6.7.2.1结构和联合说明符¶15](http://port70.net/~nsz/c/c11/n1570.html#6.7.2.1p15)以及¶17。) - Jonathan Leffler
1
即使没有填充和重新排列元素,使用指针算术运算符指向指针所指向的数组之外是非法的。根据此定义,具有非数组类型的变量被视为只有1个元素的数组,并且不允许在最后一个元素之后使用超过1个元素的指针算术运算符。 - Gerhardh
显示剩余3条评论
1个回答

1
我认为你的路径是正确的,你的代码也没问题。
你可以查看this中的答案来了解如何发送和接收数据包。
以下示例展示了如何指向结构体的一个条目。
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;

如果您想在结构体中忽略填充,请添加以下代码。
#pragma pack(push, 1)

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

#pragma pack(pop)

你可以使用打印语句 print sizeof(Packet) 来查看结果。

  • 请记住,在8位系统(如Arduino UNO或AVR)中没有填充,但在ARM MCU中存在填充。

这并没有回答问题。 - n. m.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接