ラベル バイトオーダー の投稿を表示しています。 すべての投稿を表示
ラベル バイトオーダー の投稿を表示しています。 すべての投稿を表示

2011年3月22日火曜日

CRC の計算

ランダムに生成された数値データに対し、誤りチェックのためのCRCを計算する例題です。

CRCでは、
(1)送信すべきビット列を2進数とみなし、
(2)検査用の2進数ビット列で割り算し、
(3)最後はあまりを出す。
という手順を取ります。

相手側には、送信すべきビット列と余りを送ります。
受信側でも同じ割り算を行い、余りが一致すれば正しく受信できたことになります。
(割り算と言っても「桁借り」の無い特殊な割り算です)

多項式:2進ビット列のビットは上に行くほど桁の重みが大きい。
    そこで、重みを考慮した多項式表示(足し算の形)で表現します。
(例)1011100111001011 (16bit)
   最上位は2^15、最下位は2^0=1です。
   
   すると上のビット列は
   x^15 + x^13 + x^12 + x^11 + x^8 + x^7 + x^6 + x^3 + x + 1 (x=2)
   で表せます。
これが(送信すべきビット列の)多項式です。

生成多項式:検査用のビット列(割る数)も同じように多項式の形で表します。
      (余りを生成するもとの式という意味で)生成多項式と呼びます。

例題では、多項式を用い直接計算する方式と(calculateCRC16)と、余剰テーブルを用いて高速化を図った方式(calculateCRC16t/calculateCRC32t)の2種類の計算を行っていますが、それぞれの結果は同じです。
配列のサイズが大きくなると計算量も大きくなるため、このような工夫が取られています。
また、検査用ビット数を16/32ビットとした計算の2種類用意しています。

生成された配列にCRCを付与した配列に対し、再度CRCを計算(CRCデータも含め)するとCRCが0になることを確認することにより、CRCの計算結果が正しいことが確認できます。

CRCを配列に格納する場合のバイトオーダーは、ビッグエンディアンで格納する必要があります。
ネットワークでやり取りされるデータは、通常ビッグエンディアンになりますので、ホスト内のバイトオーダーとは異なる点に注意が必要です。
例題では、htons/htonl 関数により、16/32 ビットのデータをビッグエンディアンに変更し格納しています。

ソース等をまとめたもの:DL

crc.h

crc.cpp

crcTest.cpp

実行結果

2011年3月16日水曜日

10進・16進[文字列]の変換(バイナリデータからアスキーテキストへの変換)

10進数字から16進文字列への変換(1234 → "04 D2")、
16進文字列から10進数字への変換("04 02" → 1234)、
を行う例題です。

16進数のデータはchar型データの文字列として扱います。
バイナリエディタなどでは、char 型で扱われる 0〜255 までの文字を1バイトずつ printf にて %x 形式で出力すれば良い話です。
一方古い通信機器等では、通信を行う際の形式がアスキー形式かつ1バイト(char)を変換した "AA" ではなく、2バイト(short)、4バイト(int)等の場合があり、一文字のデータを送る場合にも "000000AA" のように "00" 文字を埋めた形のアスキーテキストを送る必要があります。
また、そのアスキーデータを受信した後にバイナリデータとして変換する必要があります。

例題では、バイナリダンプで行うような1バイトずつの16進文字列への変換と、変換するバイト数(1バイト・8バイト)を指定した変換を行っています。
バイナリダンプを行うような場合は、hexdump/dump2char 関数のみを参考にしてください。

バイト数を指定する例ではバイトオーダーを考慮し、リトルエンディアン[最下位のバイト順](Intel) の並びで変換が行われた結果が表示されています(Intel OSX)。
バイトオーダーの違いによるバイト列の並びは以下のようなものです。
例:2バイト(16ビット)の数値(1)
ビッグエンディアン  00000000 00000001  (Byte4:Byte3:Byte2:Byte1)
リトルエンディアン  00000001 00000000  (Byte1:Byte2:Byte3:Byte4)

実行結果

2011年3月13日日曜日

バイトオーダーのチェック(ネットワークバイトオーダーへの変換)

バイトオーダーをチェックする際には以下のようなコードを利用することができます。
32ビット整数に数字の 1 を代入し、先頭8ビットのみを調べて数字の 1 と同じ値になるのがリトルエンディアン、0 になるのがビッグエンディアンになります。
例:2バイト(16ビット)の数値(1)
ビッグエンディアン  00000000 00000001  (Byte4:Byte3:Byte2:Byte1)
リトルエンディアン  00000001 00000000  (Byte1:Byte2:Byte3:Byte4)

下記の例題では、バイトオーダーをチェックし、その並び順に沿ったバイト列を表示しています。
また、htons/htonl 関数によりネットワーク間のデータ送受信に用いられるネットワークバイトオーダー(ビッグエンディアン)に変換し、バイト列を表示しています。

実行結果