1

共用体の構造体についてサポートが必要です。さまざまなパケットで構成されるバイトストリームを受信して​​いるので、バイトデータをunion structに入れ、structメンバーを介して必要なデータにアクセスしています。問題はuint32_tタイプのメンバーにあります-読み取りはその2バイトをスキップし、そのメンバーを介してアクセスするときに間違った値を示します。完全なデモコードは次のとおりです。

PacketUtils.h

#include <stdint.h>

typedef struct {

  uint8_t startSymbol;
  uint8_t packetType;
  uint32_t deviceId;
  uint16_t packetCRC;

} PacketData;

typedef union {

  uint8_t *bytes; // stores raw bytes
  PacketData *packet; 

} Packet;

// Puts bytes into predefined struct
void getPacketFromBytes(void *bytes, Packet *packetRef);

PacketUtils.c

#include <stdio.h>
#include "UnionStruct.h"

void getPacketFromBytes(void *bytes, Packet *packetRef)
{
  uint8_t *rawBytes = (uint8_t *)bytes;
  packetRef->bytes = rawBytes;
}

発信コード:

// sample byte data
uint8_t packetBytes[] = {0x11, 0x02, 0x01, 0x01, 0x01, 0x03, 0xbb, 0xbd};

Packet packetRef;
getPacketFromBytes(packetBytes, &packetRef);

printf("%x\n", packetRef.packet->startSymbol); // good - prints 0x11
printf("%x\n", packetRef.packet->packetType); // good - prints 0x02 
printf("%x\n", packetRef.packet->deviceId); // bad - prints bd bb 03 01
printf("%x\n", packetRef.packet->packetCRC); // bad - prints 36 80 (some next values in memory)

PacketData構造体がuint8_tまたはuint16_tタイプのメンバーで構成されている場合、すべてがOKであり、印刷には正しい値が表示されます。ただし、タイプuint32_tのdeviceIdを出力すると、2バイト(0x01 0x01)がスキップされ、最後の4バイトが取得されます。packetCRCを出力すると、指定されたバイト配列から値が出力されます。これは、packetBytes[12]やpacketBytes[13]などのメモリ内の2つの値です。なぜ2バイトスキップするのかわかりません...

4

2 に答える 2

1

32ビットの数値は4バイト境界でのみ整列されます。構造体の先頭に移動すると、希望どおりに機能する場合があります。

プロセッサは通常、データムサイズの倍数(32ビットの場合は4バイト、64ビットの場合は8バイト)でデータをフェッチするように最適化されています。コンパイラはこれを認識し、データ構造にギャップを追加して、プロセッサがデータを効率的にフェッチします。

パディングを処理せず、データ構造を移動できない場合は、次のように定義できます。

typedef struct {
    uint8_t startSymbol;
    uint8_t packetType;
    uint16_t deviceIdLow;
    uint16_t deviceIdHigh;
    uint16_t packetCRC;
} PacketData;

そしてただ書く

uint32_t deviceID = packetRef.packet->deviceIdLow | (packetRef.packet->deviceIdLow << 16);
于 2012-12-03T17:05:31.470 に答える
1

この問題は、プラットフォームのデフォルトの配置にフィールドが埋め込まれていることが原因です。最新のアーキテクチャでは、32ビットのワードアラインされたアドレスに対して読み取り/書き込みを行う場合、32ビット値が最も効率的です。

gccでは、構造が「パック」されていることを示すために特別な属性を使用することで、これを回避できます。ここを参照してください:

http://gcc.gnu.org/onlinedocs/gcc-3.3.6/gcc/Type-Attributes.html

したがって、構造体の定義は次のようになります。

typedef struct {

    uint8_t startSymbol;
    uint8_t packetType;
    uint32_t deviceId;
    uint16_t packetCRC;

} PacketData __attribute__((packed));
于 2012-12-03T17:08:46.530 に答える