2012-01-15 8 views
4

すべてのCのコーダーにこんにちは。ポータブル(LinuxとWindowsがほとんど)4bytesの抽出/比較

私のような同様の質問が最初に見つかったので、見つけられませんでした。

4バイトをポータブルな方法でフェッチ/比較するには(もちろんmemcpy/memcmpは必要ありません)?

私はCを学んだことはありません。そのことから、基本を知ることなくすべてのことが厄介な混乱になるという生きた証拠です。 とにかく、(すでに)単語を書くことは、「アルファベットで始める」と言う時間がありません。

ulHashPattern = *(unsigned long *)(pbPattern); 
     for (a=0; a < ASIZE; a++) bm_bc[a]=cbPattern; 
     for (j=0; j < cbPattern-1; j++) bm_bc[pbPattern[j]]=cbPattern-j-1; 
     i=0; 
     while (i <= cbTarget-cbPattern) { 
      if (*(unsigned long *)&pbTarget[i] == ulHashPattern) { 

上記のフラグメントは、Windows 32ビットコンパイラで必要な機能を果たします。私の望みは、64ビットのWindowsとLinuxでも同様に動作する4vs4の比較です。 何回も2,4,8バイトの転送が必要です。上記の例では、pbTargetオフセットから明示的に4バイトが必要です。 実際の質問:の代わりにどのようなタイプを使用すればいいですか?符号なしロング(私はUINT16、UINT32、UINT64に近いものと思われます)。 言い換えれば、2,4,8バイトを表現するために私が必要とする3つのタイプはどれも、環境から独立してです。

この基本的な質問は多くの問題を引き起こすと考えられますので、明確にする必要があります。

アドオン2012-JAN-16:

@Richard J. RossのIII
私はダブル混乱しています! Linuxが1または2を使用しているかどうかわからない、つまりLinuxで定義されている_STD_USINGであるとすれば、 はどのグループが可搬性であるかということです。uint8_t、...、uint64_tまたは_CSTD uint8_t、...、_ CSTD uint64_t?

1] MVSから抜粋10.0 stdint.h

typedef unsigned char uint8_t; 
typedef unsigned short uint16_t; 
typedef unsigned int uint32_t; 
typedef _ULonglong uint64_t; 

2] 10.0 stdint.h

マイクロソフトC 32ビットで
#if defined(_STD_USING) 
... 
using _CSTD uint8_t; using _CSTD uint16_t; 
using _CSTD uint32_t; using _CSTD uint64_t; 
... 

MVSから抜粋は問題がない。

; 3401 :   if (*(_CSTD uint32_t *)&pbTarget[i] == *(_CSTD uint32_t *)(pbPattern)) 

    01360 8b 04 19  mov  eax, DWORD PTR [ecx+ebx] 
    01363 8b 7c 24 14 mov  edi, DWORD PTR _pbPattern$GSCopy$[esp+1080] 
    01367 3b 07  cmp  eax, DWORD PTR [edi] 
    01369 75 2c  jne  SHORT [email protected][email protected] 

しかし、64ビットがターゲットコードの場合、それはどうなりますか:

D:\_KAZE_Simplicius_Simplicissimus_Septupleton_r2-_strstr_SHORT-SHOWDOWN_r7>cl /Ox /Tcstrstr_SHORT-SHOWDOWN.c /Fastrstr_SHORT-SHOWDOWN /w /FAcs 
Microsoft (R) C/C++ Optimizing Compiler Version 15.00.30729.01 for x64 
Copyright (C) Microsoft Corporation. All rights reserved. 

strstr_SHORT-SHOWDOWN.c 
strstr_SHORT-SHOWDOWN.c(1925) : fatal error C1083: Cannot open include file: 'stdint.h': No such file or directory 

D:\_KAZE_Simplicius_Simplicissimus_Septupleton_r2-_strstr_SHORT-SHOWDOWN_r7> 

Linuxのstdint.hではどうしてですか?

私はあきらめて、それをコメントしませんでした://#include <stdint.h>、そしてコンパイルはOK行きました:

; 3401 :   if (!memcmp(&pbTarget[i], &ulHashPattern, 4)) 
    01766 49 63 c4  movsxd rax, r12d 
    01769 42 39 2c 10 cmp  DWORD PTR [rax+r10], ebp 
    0176d 75 38  jne  SHORT [email protected][email protected] 

; 3401 :   if (*(unsigned long *)&pbTarget[i] == ulHashPattern) 
    01766 49 63 c4  movsxd rax, r12d 
    01769 42 39 2c 10 cmp  DWORD PTR [rax+r10], ebp 
    0176d 75 38  jne  SHORT [email protected][email protected] 

をこの非常に 'unsigned long型*' トラブル私のgcc -m64は右、QWORDないDWORDを取得しますので、?
1]

; 3400 :   if (!memcmp(&pbTarget[i], pbPattern, 4)) 
    01360 8b 04 19  mov  eax, DWORD PTR [ecx+ebx] 
    01363 8b 7c 24 14 mov  edi, DWORD PTR _pbPattern$GSCopy$[esp+1080] 
    01367 3b 07  cmp  eax, DWORD PTR [edi] 
    01369 75 2c  jne  SHORT [email protected][email protected] 

2]

; 3400 :   if (!memcmp(&pbTarget[i], &ulHashPattern, 4)) 
    01350 8b 44 24 14 mov  eax, DWORD PTR _ulHashPattern$[esp+1076] 
    01354 39 04 2a  cmp  DWORD PTR [edx+ebp], eax 
    01357 75 2e  jne  SHORT [email protected][email protected] 

3]

; 3401 :   if (*(uint32_t *)&pbTarget[i] == ulHashPattern) 
    01350 8b 44 24 14 mov  eax, DWORD PTR _ulHashPattern$[esp+1076] 
    01354 39 04 2a  cmp  DWORD PTR [edx+ebp], eax 
    01357 75 2e  jne  SHORT [email protected][email protected] 

@Mysticial
ちょうどマイクロソフトCLの32ビットV16によって行わ三つの異なる翻訳を見せたかったです

Th最初の目標は、1つのmov命令(*(uint32_t *)&pbTarget [i])を抽出し、長さが4バイトのレジスタ変数、すなわち1つのRAMが単一命令内の1つの比較にアクセスすることを比較することであった。 Nastilyは、memcmp()の3回のRAMアクセス(4バイト以上を指すpbPatternに適用)を2に減らしただけで、インライン展開に感謝しました。 pbPatternの最初の4バイト(2のように)にmemcmp()を使用する場合、ulHashPatternは型レジスタではなく、3]はそのような制限を必要としません。

; 3400 :   if (!memcmp(&pbTarget[i], &ulHashPattern, 4)) 

上記の行は、(ulHashPatternは以下のように定義される:unsigned long型ulHashPatternを登録;):エラーになります

strstr_SHORT-SHOWDOWN.c(3400) : error C2103: '&' on register variable 

はい、あなたは右のとおりです。memcmp()状況は(これに限定して保存します) - フラグメント2]は、3]マイナスダーティスタイルと同じです。 明らかに、手動でコード化されたときに関数を使用しないという私の傾向は過去のものですが、私はそれが好きです。

まだコンパイラがうまくいきません。ulHashPatternをレジスタ変数として定義しましたが、RAMから毎回ロードされますか?たぶん私は何かが恋しいですが、これは非常に(mov eax、DWORD PTR _ulHashPattern $ [esp + 1076])の行がパフォーマンスを低下させます。私の見解では醜いコードです。

+0

stdint.hで定義されているuint64_tとその対応部分を確認してください。 –

+0

Richard Ross IIIさん、私は(私が家に帰ると)相手を探します。おそらく彼らはstdint.hにいるので、 ? – Georgi

答えて

1

厳密にペダンティックであるためには、使用できる唯一のタイプはcharです。あなたは次のタイプ-駄洒落でviolating strict-aliasingているので、これはです:あなたがchar*で任意のデータ型を別名設定できるよう

*(unsigned long *)(pbPattern); 
*(unsigned long *)&pbTarget[i] 

char*は、この規則の唯一の例外です。

GCCで警告を出す場合は、コードスニペットで厳密なエイリアス警告が表示されるはずです。 (私の知る限り、MSVCは厳しいエイリアシングを警告しません。)


あなたがすべきではない、私はかなりあなたがそのコード・スニペットでやろうとしている正確に何を伝えることはできませんが、アイデアはまだ保持していますunsigned longまたは他のデータ型を使用して、異なるタイプのより大きなデータチャンクをロードして比較することができます。

現実的には、memcmp()を使用してください。それは簡単で、すべてを強制的に非効率にしてchar*にすることができます。

memcmp()を使用できない理由はありますか?


あなたは、厳密なエイリアシングに違反してOKなら

、あなたは <stdint.h>で定義された固定整数型(のような uint32_t)を使用することができます。ただし、これらはバイト数ではなくビット数に固定されていることに注意してください。

+0

あなたの助けてくれてありがとう、彼らがどれくらい生産しているか分かっていたら、私は刑務所と呼ぶべきです。私のコーディングスタイルは厳密に違反しています(厳密なエイリアシングに関してだけでなく)。あなたの質問については:memcmp()はスピードが欲しいので質問から外れています。実際、これは非常に4vs4の比較がインラインmemcmp()の始まりです。 – Georgi

+0

この場合、多くの試行錯誤(そして多くのベンチマーク)の後に、私はmemcmpコードよりも速いと思いました。[リンク](http://www.sanmayce.com/Railgun/index.html) – Georgi

+0

Ahあなたがベンチマークしていれば(適切に)、それでいいです。確かにコンパイラよりも優れている可能性があります。 'memcpy()'を発行するだけで、通常はより安全で読みやすくなります。私の答え[ここ](http://stackoverflow.com/questions/8528590/what-is-the-advantage-of-using-memset-in-c)を参照してください。 – Mysticial

関連する問題