1

私はbashでCRC16チェックサムを実装しようとしています。既存のC++コードから移植しています。私はもうすぐそこにいますが、私は別の答えを得ています。

C++コードとbashスクリプトのチェックサムが異なる理由がよくわかりません。

別の目は大きな助けになるでしょう。

C++コードは次のとおりです。

uint16_t Encoder::checksum(std::string thestring)
{
    uint8_t d, e, f;
    uint16_t c, r, crccalc;
    c = 0xffff;

    for (unsigned int i = 0; i < thestring.length(); i++)
    {
        d = thestring[i];
        e = c ^ d;
        f = e ^ (e << 4);
        r = (c >> 8) ^ (f << 8) ^ (f << 3) ^ (f >> 4);
        c = r;
    }
    c ^= 0xffff;
    crccalc = c;
    return crccalc;
}

そして、これが私のbashコードです:

function calc_crc16()
{
    string=$1
    while read -d "" -n 1 ; do astring+=( "$reply" ) ; done <<< "$string"

    cnt=${#astring[@]}
    c=0xffff

    for ((x=0;x<$cnt;x++)); do
        char=${astring[$x]}
        e=$(($c ^ $char))
        s=$(($e << 4))
        f=$(($e ^ $s))
        t1=$(($c >> 8))
        t2=$(($f << 8))
        t3=$(($f << 3))
        t4=$(($f >> 4))
        r1=$(($t1 ^ $t2 ^ $t3 ^ $t4))
        c=$r1
    done
    c=$c ^ 0xffff
    echo "checksum = $c"
}

それはintのサイズと関係があるのでしょうか?bashでそれについてできることはあまりないと思います。

実際の番号を取得していますが、正しく機能することがわかっているC++と一致しません。誰かが私が物事を台無しにしているかもしれない何かを見ますか?

4

4 に答える 4

4

最初の問題は上部にあります

while read -d "" -n 1 ; do astring+=( "$reply" ) ; done <<< "$string"

$reply読み取り用の変数名を指定しなかったため、名前は$REPLYです。

次のエラーは最後です

c=$c ^ 0xffff

これは

c=$(($c ^ 0xffff))

少なくともこの方法では、エラーなしで実行されます。正確性と適切性は別のものです。

正しさの問題:入力文字列にスペースがある場合はどうなりますか?これはひどく壊れます。常に変数exapnsionsを引用します

変化する

char=${astring[$x]}

char="${astring[$x]}"

不思議なことに、このルールは$(())構造内で異なります。$これらの場合、ビット演算は変数を参照せずに参照する必要があります

e=$(( c ^ char ))
s=$(( e << 4 ))
f=$(( e ^ s ))
t1=$(( c >> 8 ))
t2=$(( f << 8 ))
t3=$(( f << 3 ))
t4=$(( f >> 4 ))
r1=$(( t1 ^ t2 ^ t3 ^ t4))

以降

c=$(( c ^ 0xffff ))

これにより、変数が拡張され、空白が爆発しないようになります。

-r一般に、に渡す必要があります。それが何をするかreadを確認してください。help read

$1配列に処理する前に、なぜ余分なコピーを作成するのですか?使用する

while read -d "" -n 1 ; do astring+=( "$REPLY" ) ; done <<< "$1"

十分なものです。

処理する前に、入力を配列に変換する必要はおそらくありません。代わりに、ループ内の文字列から文字をスライスすることができます。これは、C++バージョンが実行していることに近いものです。交換

char="${astring[$x]}"

char="${1:$x:1}"

これは関数パラメータを直接操作しています。そのコピーを作成しなくなったので$cnt、別の方法を取得する必要もあります

cnt=${#1}

しかし、文字がbashの整数ではないという事実のように、実際にはこれよりもさらに大きな問題があります。変換するには、次の構文を使用する必要があります。

printf '%d' \'a

a変換する文字はどこにありますか。これをスクリプトのコンテキストに挿入すると、

char=$(printf '%d' \'"${1:$x:1}")

今、私たちはどこかに到達していますが、私は本当にあなたにこれらすべてが本当に価値があるかどうかを検討するように頼まなければなりません。あなたがそれを機能させることができたとしても、あなたは何を得るのですか?

于 2011-12-19T17:34:31.963 に答える
3

将来の参考のために、これが私が思いついたawkスクリプトです。

これは私が持っているC++コードと同じくらい速く動作します。これは基本的に瞬時です。同じ文字列に対してbashを実行するには約10秒かかります。awkははるかに高速です。

function awk_calc_crc16()
{
    output=$(echo $1 | awk 'function ord(c){return chmap[c];}
    BEGIN{c=65535; for (i=0; i < 256; i++){ chmap[sprintf("%c", i)] = i;}}
    {
        split($0, chars, "");
        for(i = 1; i <= length(chars); i++)
        {
            cval=ord(chars[i])
            e=and(xor(c, ord(chars[i])), 0x00FF);
            s=and(lshift(e, 4), 0x00FF);
            f=and(xor(e, s), 0x00FF);
            r=xor(xor(xor(rshift(c, 8), lshift(f, 8)), lshift(f, 3)), rshift(f, 4));
            c=r;
        }
    }
    END{c=xor(c, 0xFFFF); printf("%hu", c);}')
    echo $output;
}
于 2011-12-20T13:49:52.063 に答える
2

わかった。Sorpigalの助けを借りて、私は動作するバージョンを手に入れました。

これはすべてawkスクリプト内で実行できると思いますが、これははるかに高速に実行される可能性があります。私は次にそれを試みるかもしれません。

助けてくれてありがとう。ここで解決策を盗むつもりはありませんが、私はそれに取り組み、それを我慢する価値があると考えています。

とにかく、これが動作するバージョンです:

function calc_crc16()
{
    while read -r -d "" -n 1 ; do astring+=( "$REPLY" ) ; done <<< "$1"

    cnt=${#1}
    c=65535

    for ((x=0;x<$cnt;x++)); do
        char=$(printf '%d' \'"${1:$x:1}")
        e=$(((c ^ char) & 0x00FF))
        s=$(((e << 4) & 0x00FF))
        f=$(((e ^ s) & 0x00FF))
        r1=$(((c >> 8) ^ (f << 8) ^ (f << 3) ^ (f >> 4)))
        c=$r1
    done
    c=$((c ^ 0xffff))
    echo "checksum = $c"
}
于 2011-12-20T13:15:07.237 に答える
0

より短い(そしてより速い)バージョン
変更:
-最初のwhileループは必要ありませ ん-r1は
必要ありません-cntは必要ありません -bash変数に大文字を使用します -char = $(printf …<br>-0xFFの先頭の0を削除


function calc_crc16() {
  CRC=0xFFFF

  for ((X=0; X<${#1}; X++)); do
    CHAR=$(printf '%d' "'${1:$X:1}")
    E=$(((CRC ^ CHAR) & 0xFF))
    S=$(((E << 4)     & 0xFF))
    F=$(((E ^ S)      & 0xFF))
    CRC=$(((CRC >> 8) ^ (F << 8) ^ (F << 3) ^ (F >> 4)))
  done

  let CRC^=0xFFFF
  printf "0x%X\n" $CRC
}
于 2019-11-18T21:30:24.417 に答える