1

struct値の配列として扱うことで、a を設定できunsigned charますか?

マイクロコントローラから RS232 UART 経由で文字データを受信して​​います。C を使用して、データ型 uint16_t、uin32_t、int32_t[]、... で char 配列を逆シリアル化するにはどうすればよいですか?

例えば

uin16_t StartID = ARRAY[0];
uin16_t EndID = ARRAY[246];

・・・こんなことありませんか?C# には逆シリアル化のための効果的な関数がありますが、C ではそうではありません

後で

if (StartID == 11)
    printf("good"); 
else 
    printf("bad");

この構造体は、後でデータを使用して簡単に操作できるようにしました。ARRAY[248] から構造体にデータを取得する方法はありますか?

typedef struct
{
  //Header 6byte
  uint16_t StartID; // Check if its 1 or in hex 0b
  uint16_t ID;      
  uint16_t LoadID;  

  //Payload 240 byte
  int32_t POS01[3];  
  int32_t POS02[3];
  int32_t POS03[3];
  int32_t POS04[3];
  int32_t POS05[3];
  int32_t POS06[3];
  int32_t POS07[3];
  int32_t POS08[3];
  int32_t POS09[3];
  int32_t POS10[3];
  int32_t POS11[3];
  int32_t POS12[3];
  int32_t POS13[3];
  int32_t POS14[3];
  int32_t POS15[3];
  int32_t POS16[3];
  int32_t POS17[3];
  int32_t POS18[3];
  int32_t POS19[3];
  int32_t POS20[3];

  //End 2byte
  uint16_t EndID; // Check if its 47 or in hex 2F

} DATA_POS; //TOTAL = 248byte
4

2 に答える 2

0

同様のアプローチがいくつかあります。union明示的なポインターの使用を避けるC を使用できます。「memcpy」を使用して、の内容を構造体unsigned char[]のメモリにコピーできます。DATA_POSまたは、シリアル ポートから読み取り中にそのメモリに直接書き込むこともできます。

エンディアンが懸念事項であるかどうかについて言及しなかったので、それについても説明します。

Aunionを使用すると、異なるデータ型として同じメモリ ブロックにアクセスできます。例えば:

#include <stdio.h>

#define chars_per_int (sizeof(int) / sizeof(char))

// Note that every member of a union exists at the same memory location,
// so changing the value of one will change the value of all
union IntAsChars {
    unsigned int integerValue;
    unsigned char characterValue[chars_per_int];
};

int main() {
    int i;
    union IntAsChars value;

    value.integerValue = 0x1234abcd;

    for (i = 0; i < chars_per_int; i++) {
        printf("Character value is: %x\n", value.characterValue[i]);
    }

    return 0;
}

上記のコードは、同じsizeof(int)バイトを文字値の文字列として扱い、それぞれの数値を出力します。

コードに基づいて、次のようなユニオンを探しています

union data_representation {
    unsigned char char_data[248];
    DATA_POS data_pos;
};

union data_representation data;

これによりdata.char_data、シリアル部分から入力できますがdata.data_pos.StartID、コードから参照できます。

ただし、異なるアーキテクチャでは、整数の個々のバイトを異なる順序で格納できることに注意してください。Intel アーキテクチャは、伝統的にスモール エンディアン表現を使用します。上記のコードの出力は、x86 では異なります。

Character value is: cd
Character value is: ab
Character value is: 34
Character value is: 12

および SPARC:

Character value is: 12
Character value is: 34
Character value is: ab
Character value is: cd

最も安全な一般的な方法は、システム間で (この場合はシリアル ポート経由で) ビッグ エンディアン データを送信し、ntohs/ntohlを使用してローカル ホストの表現に変換することです。これらの関数は、「ネットワーク」(ビッグエンディアン) の短い ( ntohs) または長い ( ntohl) データを、ローカル システムで使用されている形式に変換します。ntohnetwork to host を意味し、接尾辞はshort またはlong 値用です。ホスト形式からビッグエンディアンへの変換には、対応する関数htonsと関数があります。htonl

したがって、引き続き を入力しますが、とをdata.char_data使用してデータを読み取り、ネイティブ値を取得します。ntohs(data.data_pos.StartID)ntohl(data.data_pos.POS04[1])

ntohl以下の/ ntohs sprinkled throughout your code later. For example, theconvert_to_host_format` 関数は、248 文字の入力配列を適切なエンディアンを持つ DATA_POS 構造体に変換します。

void convert_POS_to_host_format (int32_t dest[3], int32_t src[3]) {
    dest[0] = ntohl(src[0]);
    dest[1] = ntohl(src[1]);
    dest[2] = ntohl(src[2]);
}

DATA_POS convert_to_host_format (char buffer[248]) {
    DATA_POS host_data;
    union data_representation data;

    memcpy((void*)data.char_data, (void*)buffer, sizeof(buffer));

    host_data.StartID = ntohs(data.data_pos.StartID);
    host_data.ID = ntohs(data.data_pos.ID);
    host_data.LoadID = ntohs(data.data_pos.LoadID);

    convert_POS_to_host_format (host_data.POS01, data.data_pos.POS01);
    convert_POS_to_host_format (host_data.POS02, data.data_pos.POS02);
    convert_POS_to_host_format (host_data.POS03, data.data_pos.POS03);

    /* ... */

    convert_POS_to_host_format (host_data.POS19, data.data_pos.POS19);
    convert_POS_to_host_format (host_data.POS20, data.data_pos.POS20);

    host_data.EndID = ntohs(data.data_pos.EndID);

    return host_data;
}

をスキップしたい場合は、 の内容を保持しているメモリに直接書き込むことでunionmemcpyを使用して同じ結果を得ることができますDATA_POS

void convert_POS_to_host_format (int32_t POS[3]) {
    POS[0] = ntohl(POS[0]);
    POS[1] = ntohl(POS[1]);
    POS[2] = ntohl(POS[2]);
}

DATA_POS convert_to_host_format (char buffer[sizeof(DATA_POS)]) {
    DATA_POS host_data;

    /* Write the contents of 'buffer' directly into the memory location of
     * 'host_data'.
    memcpy((void*)host_data, (void*)buffer, sizeof(DATA_POS));

    /* Convert values to host byte order in place. */
    host_data.StartID = ntohs(host_data.StartID);
    host_data.ID = ntohs(host_data.ID);
    host_data.LoadID = ntohs(host_data.LoadID);

    convert_POS_to_host_format (host_data.POS01);
    convert_POS_to_host_format (host_data.POS02);
    convert_POS_to_host_format (host_data.POS03);

    /* ... */

    convert_POS_to_host_format (host_data.POS19);
    convert_POS_to_host_format (host_data.POS20);

    host_data.EndID = ntohs(data.data_pos.EndID);

    return host_data;
}

UART データの読み取り中にポインターを使用して、DATA_POS 構造体に直接書き込むこともできます。以下は、構造体 ( ) のアドレスを&data符号なし文字ポインタとして扱います。

上記の convert_to_host_format 構造体のような関数を使用して、エンディアンの問題に対処することをお勧めします。ただし、複数のアーキテクチャで実行できる必要がない場合は、次の方法でニーズを満たすことができます。

DATA_POS data;
int i;
char *write_buffer;

write_buffer = (unsigned char*) &data;

for (i = 0; i < sizeof(DATA_POS); i++) {
    write_buffer[i] = read_byte_from_uart();
}

明確にしてほしいことがあればお知らせください。

于 2012-09-01T22:15:30.877 に答える
0

Cには次の機能がありますpointers

uin16_t *StartID = (void*)&ARRAY[0];
uin16_t *EndID = (void*)&ARRAY[246];

別の形式でデータにアクセスするその他の方法には、次のものがありますunions

   union 
   {
      uint32_t *u32;
      uint16_t *u16;
      uint8_t  *u8;
   } u;

ご覧のとおり、機能には専用の機能が必要ない場合があります。

ただし、このような方法でデータにアクセスするため、一部のプラットフォームではアラインメントの問題が発生する可能性があることに注意してください。

于 2012-09-01T03:53:16.243 に答える