同様のアプローチがいくつかあります。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
) データを、ローカル システムで使用されている形式に変換します。ntoh
はn
etwork to
h
ost を意味し、接尾辞はs
hort またはl
ong 値用です。ホスト形式からビッグエンディアンへの変換には、対応する関数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, the
convert_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;
}
をスキップしたい場合は、 の内容を保持しているメモリに直接書き込むことでunion
、memcpy
を使用して同じ結果を得ることができます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();
}
明確にしてほしいことがあればお知らせください。