2016-05-08 17 views
1

私は、符号なしlongをとるアセンブリで関数を書いています。 このlongはUTF-8文字です。アセンブリAT&Tのx86 - どのように特定のバイトを比較するには?

1,2,3,4バイトのUTF-8文字かどうかをチェックしたいと思います。これまでのところ私はこれを持っている:(私はコードに変更されましたエンディアンの影響を受けることがないように、私が思うに...)

movl 12(%ebp),%eax # Move long u to %eax 
movl %eax,buff  # Move long u to buff 
andl $128,buff  # &-mask 1 MSB (from LSByte) 
cmpl $0,buff   # Compare buff to 0 
je  wu8_1byte  # If 0, 1 byte UTF8 

movl 12(%ebp),%eax # Move long u to %eax 
movl %eax,buff  # Move long u to buff 
andl $0xE000,buff # &-mask 3 MSB (from byte LSByte 2) 
cmpl $0xC000,buff # Compare the 3 MSB to binary 110 
je  wu8_2byte  # If =, 2 byte UTF8 

movl 12(%ebp),%eax # Move long u to %eax 
movl %eax,buff  # Move long u to buff 
andl $0xF00000,buff # &-mask 4 MSB (from byte MSByte 3) 
cmpl $0xE00000,buff # Compare the 4 MSB to binary 1110 
je  wu8_3byte  # If =, 3 byte UTF8 

jmp  wu8_4byte  # If no, 4 byte UTF8 

12(%のEBP)で長い私が仕事をしたいです。 Buffは4バイトの変数です。

これは1バイトで動作しますが、他の動作では動作しません。

どのようなタイプのUTF-8 charがあるかを知るためのヒントを教えてください。

UTF-8エンコーディング:

      0xxxxxxx # 1 byte 
        110xxxxx 10xxxxxx # 2 byte 
     1110xxxx 10xxxxxx 10xxxxxx # 3 byte 
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx # 4 byte 
+0

「このロングはUTF-8文字です」と言うと、間違いなくビッグエンディアン形式でエンコードされていますか? Intelではこれが珍しいからです。 –

+0

私はそれがどのようなエンディアンであるかを確認しています。私はgcc -m32を使ってそれをコンパイルしています。そして、私はCプログラムでassemby関数をテストします。 –

+0

先頭のバイトの部分をテストするために13ビットをシフトしているという事実は、ビッグエンディアンの順序で格納されたUTF-8バイトシーケンスを持っていると思っていることを私に伝えます。あなたのシステムのアーキテクチャはリトルエンディアンです。それが私にとって奇妙に見える理由です。 –

答えて

1

それは単純な理由のためにそれらのいずれかのために働くべきではありません。

あなたは32ビットの値をとり、それを正しくシフトします。それからあなたは、あなたが比較しているものよりもずっと多くのビットがまだ残っていることを忘れて、それを定数と比較します。

あなたは、値が唯一の希望のビットを取るためにする必要があります。

movl 12(%ebp),%eax 
movl %eax,buff 
shrb $13,buff #UTF8 2 byte looks like 110xxxxx 10xxxxxx 
andl $7, buff # Take only the three lowest bits 
cmpl $6,buff #Therefore shift 13 spaces right and check 
je wu8_2byte #if buff=6 (110 = 6) 

私も速くそれを作るためにメモリ位置にレジスタの中でそれを処理しないでしょう。あなたはちょうど、そして何の変化も伴わずにそれを行うことができます。

+0

ロングは、すべて左から右に0パディングされていると仮定しました。しかし、私はあなたに解決策を試みましたが、それはどちらもうまくいきませんでした。 –

1

エラーチェックの頻度に応じて、test命令でビットをテストすることができます。私は、unsigned longが、UTF-8でエンコードされたバイトのシーケンスからロードされたと仮定しました。最下位バイトは、リトルエンディアンマシンのchar*からunsigned long*へのエイリアスと同じ結果でなければなりません。

これらの前提が間違っている場合は、それに応じてコードを変更する必要があります。また、どのバイトが先頭バイトであるかわからない場合もあります。

など。

movl 12(%ebp),%eax 
testl $128,%eax 
jz wu8_1byte 
testl $32,%eax  # We know that the top bit is set, it's not valid for it to be 
        # 10xxxxxx so we test this bit: 11?xxxxx 
jz wu8_2byte 
testl $16,%eax  # 111?xxxx 
jz wu8_3byte 
# Must be 4 byte 
jmp wu8_4byte 

このコードスニペットは、元のコードと同じ前提です。

movl 12(%ebp),%eax 

testl $0x80,%eax 
jz wu8_1byte 
        # We can assume that the last byte is of the form 10xxxxxx 
testl $0x7000,%eax # Testing this bit in byte n - 1: 1?xxxxxx 
jnz wu8_2byte 

testl $0x700000,%eax # Testing this bit in byte n - 2: 1?xxxxxx 
jnz wu8_3byte 
# Must be 4 byte 
jmp wu8_4byte 
+1

'testl $ 128、%eax'は、'%al'をテストするか、 'testl%al、%al' /' jns'を使ってローの最上位ビットに分岐することで短くなります。 8に直接的な定数はありません。しかし、 'test $ imm8、%al'は特別なオペコードを持っているので、まだ2B命令です。また、 'testl $ 0x7000、%eax'は' test 0x70、%ah'となり、もう2バイトのマシンコードを保存することができます。 (部分的なレジスタの読み込みは常に問題ありませんが、遅くなる可能性のある部分的なレジスタを書き込んでいますので、test $ imm16、%ax'を避けてください:16MBのオペランドサイズでLCPのストールが発生します) –

0

私はUTF-8にアップ読んで、簡単に解決見つけることによってそれを解決:1つのバイト文字、UTF-8文字をエンコードする方法を

cmpl $0x7F,12(%ebp)  # Compare unsigned long to 1 byte UTF-8 max value 
jbe  wu8_1byte 

cmpl $0x7FF,12(%ebp) # Compare unsigned long to 2 byte UTF-8 max value 
jbe  wu8_2byte 

cmpl $0xFFFF,12(%ebp) # Compare unsigned long to 3 byte UTF-8 max value 
jbe  wu8_3byte 

cmpl $0xFFFFFF,12(%ebp) # Compare unsigned long to 4 byte UTF-8 max value 
jbe  wu8_4byte 

は0x7Fをの最大値を持っています最大2バイト0x7FF、最大3バイト0xFFFF、最大4バイト0xFFFFFF。したがって、これらの値と符号なしlongを比較するだけで、文字のデコードに必要なバイト数を判断できます。

+0

実際のデータバイトは次のようになります。例:unsigned long:xxxxxxxx(byte0)xxxxxxxx(byte1)xxxxxxxx(byte2)xxxxxxxx(byte3)ここで、12(%ebp)はバイト0、15(%ebp)はバイト3です。 UTF-8データバイトはどこにありますか?彼らはいつもバイト0から始まるのですか? 4バイトUTF-8:11110xxx 10xxxxxx 10xxxxxx 10xxxxxxおよび1バイトUTF-8:0xxxxxxx 00000000 00000000 00000000のように、 –

関連する問題