2

私は C で小さなテキスト マッチング プログラムを作成していました。これは基本的に、いくつかの文字列 (char 配列の形式) にいくつかの文字が存在するかどうかをチェックします。現在は機能しており、次のようなコードブロックがあります。

if (c == 'A') return 1;
else if (c == 'B') return 1;
else if (c == 'C') return 1;
....
....
else if (c == 'Z') return 1;
else return 0;

上のブロックは速いですか?または、これはより高速になりますか?

if (c == 'A' || c == 'B' || c == 'C' ||....|| c == 'Z') return 1;
else return 0;

高速とは、文字通り高速を意味します。つまり、プログラムの開始から終了まで単純なタイマーを実行すると、実行時間が短くなる可能性がありますか?

4

6 に答える 6

7

次のことをお勧めします。

#include <ctype.h>

...

return isupper(c)

それらすべてを手動でチェックする代わりに。標準 C ライブラリ関数はかなり高速であるため、パフォーマンスは許容範囲内です。

于 2013-05-20T20:06:56.983 に答える
5

経験則として、本当に価値があるかどうか確信が持てない場合は、これらの小さなパフォーマンスの問題について心配する必要はありません。

いずれにせよ、任意の A ~ Z 文字を確認したい場合は、これ(これは、使用される文字のエンコーディングについて想定していることに注意してください。これは、AandZまたは this の間に外部記号を含めることはできません)。

if (c >= 'A' && c <= 'Z')

確かにもっと簡単な方法です。

if else チェーンが式の値に長く続くことを忘れないでくださいswitch。ステートメントを使用することもできます。

switch (exp) {
  case 'A':
  case 'B':
  case 'C':
  ...
    return 1;
  default: return 0;
}

コンパイラによってはルックアップ テーブルを使用できるため、特定の状況ではAswitchがわずかに高速になる可能性がありますが、実際にはマイクロ秒について話しているのです。

完全を期すために、C 標準ライブラリには 2 つのメソッドがisupperあり、isaplhaどちらも使用できます。

if (isupper(c)) // c is an alphabetic uppercase character
于 2013-05-20T19:52:47.903 に答える
4

最適化コンパイラは、両方の形式を同様に処理します。

このようなマイクロ最適化はコンパイラーに任せてください。ソースコードの可読性も重要です。

(もちろん、GCC の場合は最適化を有効にする必要があります。たとえば、最近のGCC 4.8 では でコンパイルしますgcc -O2)。

そして、何が最善かを確認するために、ベンチマークを実行する必要があります (他の多くの要因、特にキャッシュの局所性も重要であるため)。より高度なアルゴリズムを使用することもできます (たとえば、 のようなEまれな文字の前に、 のようなより頻繁な文字をテストしますZ)。詳細については、検索ツリーを探してください。

たとえば、生成されたアセンブリ コードgcc -O2 -fverbose-asm -Sを調べる (使用して取得する) か、内部表現を調べます。たとえば、MELT プローブを使用します(または、-fdump-tree-all多くのダンプ ファイルを に渡しますgcc)。

GCC 拡張機能を使用すると、特定の例では、次のようなケース範囲をコーディングすることもできます。

 switch (c) {
    case 'A' ... 'Z': return 1;
    default: return 0;
 }

上記のケースの範囲は、文字エンコーディングがASCIIのスーパーセットであることを前提としています。EBCDIC では機能しません

実際、スイッチの最適化は複雑です。この紙などを参照してください。

そして実際には、 (C99 標準で)からisalpha(3)を使用したいと考えています。<ctype.h>

手紙とは何かをテストするのはそれほど簡単ではありませéИ。私にとっては1つです(どちらも母音であり、UTF8ではどちらも1バイト以上必要です)

一般的なUTF-8エンコーディングには注意してください。一部の文字 (特に英語以外の言語やアルファベット) は、数バイトでエンコードされます。たとえば、Glib Unicode Manipulation関数を見てください。

于 2013-05-20T19:52:33.513 に答える
0

条件の数が多い場合は、switch ブロックの方が適しています。

switch(c) {
   case 'A':
   case 'B':
   // (...)
   case 'Z': return 1;
   default: return 0;
}
于 2013-05-20T19:53:06.963 に答える
-1

他の人が述べたように、違いはありません。両方の条件で同じ数のcmp命令が生成されifます (コンパイラによる最適化は考慮されていません)。

編集:

次のC関数を検討してください。

int is_letter2(int c)
{
  if(c == 'A') return 1;
  else if(c == 'B') return 1;
  else if(c == 'C') return 1;
  else if(c == 'D') return 1;
  else if(c == 'E') return 1;
  else if(c == 'F') return 1;
  else if(c == 'G') return 1;
  else if(c == 'H') return 1;
  else if(c == 'I') return 1;
  else if(c == 'J') return 1;
  else if(c == 'K') return 1;
  else if(c == 'L') return 1;
  else if(c == 'M') return 1;
  else if(c == 'N') return 1;
  else if(c == 'O') return 1;
  else if(c == 'P') return 1;
  else if(c == 'Q') return 1;
  else if(c == 'R') return 1;
  else if(c == 'S') return 1;
  else if(c == 'T') return 1;
  else if(c == 'U') return 1;
  else if(c == 'V') return 1;
  else if(c == 'W') return 1;
  else if(c == 'X') return 1;
  else if(c == 'Y') return 1;
  else if(c == 'Z') return 1;
  else return 0;
}

int is_letter(int c)
{
  if(c == 'A' ||c == 'B' ||c == 'C' ||c == 'D' ||c == 'E' ||c == 'F' ||c == 'G' ||c == 'H' ||c == 'I' ||c == 'J' ||c == 'K' ||c == 'L' ||c == 'M' ||c == 'N' ||c == 'O' ||c == 'P' ||c == 'Q' ||c == 'R' ||c == 'S' ||c == 'T' ||c == 'U' ||c == 'V' ||c == 'W' ||c == 'X' ||c == 'Y' ||c == 'Z')
    return 1;
 else return 0;
}

そして、アセンブリの出力: ほとんど同じです。チェックアウト:

is_letter2:
.LFB1:
    .cfi_startproc
    pushl   %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    cmpl    $65, 8(%ebp)
    jne .L3
    movl    $1, %eax
    jmp .L4
.L3:
    cmpl    $66, 8(%ebp)
    jne .L5
    movl    $1, %eax
    jmp .L4
.L5:
    cmpl    $67, 8(%ebp)
    jne .L6
    movl    $1, %eax
    jmp .L4
.L6:
    cmpl    $68, 8(%ebp)
    jne .L7
    movl    $1, %eax
    jmp .L4
.L7:
    cmpl    $69, 8(%ebp)
    jne .L8
    movl    $1, %eax
    jmp .L4
.L8:
    cmpl    $70, 8(%ebp)
    jne .L9
    movl    $1, %eax
    jmp .L4
.L9:
    cmpl    $71, 8(%ebp)
    jne .L10
    movl    $1, %eax
    jmp .L4
.L10:
    cmpl    $72, 8(%ebp)
    jne .L11
    movl    $1, %eax
    jmp .L4
.L11:
    cmpl    $73, 8(%ebp)
    jne .L12
    movl    $1, %eax
    jmp .L4
.L12:
    cmpl    $74, 8(%ebp)
    jne .L13
    movl    $1, %eax
    jmp .L4
.L13:
    cmpl    $75, 8(%ebp)
    jne .L14
    movl    $1, %eax
    jmp .L4
.L14:
    cmpl    $76, 8(%ebp)
    jne .L15
    movl    $1, %eax
    jmp .L4
.L15:
    cmpl    $77, 8(%ebp)
    jne .L16
    movl    $1, %eax
    jmp .L4
.L16:
    cmpl    $78, 8(%ebp)
    jne .L17
    movl    $1, %eax
    jmp .L4
.L17:
    cmpl    $79, 8(%ebp)
    jne .L18
    movl    $1, %eax
    jmp .L4
.L18:
    cmpl    $80, 8(%ebp)
    jne .L19
    movl    $1, %eax
    jmp .L4
.L19:
    cmpl    $81, 8(%ebp)
    jne .L20
    movl    $1, %eax
    jmp .L4
.L20:
    cmpl    $82, 8(%ebp)
    jne .L21
    movl    $1, %eax
    jmp .L4
.L21:
    cmpl    $83, 8(%ebp)
    jne .L22
    movl    $1, %eax
    jmp .L4
.L22:
    cmpl    $84, 8(%ebp)
    jne .L23
    movl    $1, %eax
    jmp .L4
.L23:
    cmpl    $85, 8(%ebp)
    jne .L24
    movl    $1, %eax
    jmp .L4
.L24:
    cmpl    $86, 8(%ebp)
    jne .L25
    movl    $1, %eax
    jmp .L4
.L25:
    cmpl    $87, 8(%ebp)
    jne .L26
    movl    $1, %eax
    jmp .L4
.L26:
    cmpl    $88, 8(%ebp)
    jne .L27
    movl    $1, %eax
    jmp .L4
.L27:
    cmpl    $89, 8(%ebp)
    jne .L28
    movl    $1, %eax
    jmp .L4
.L28:
    cmpl    $90, 8(%ebp)
    jne .L29
    movl    $1, %eax
    jmp .L4
.L29:
    movl    $0, %eax
.L4:
    popl    %ebp
    .cfi_def_cfa 4, 4
    .cfi_restore 5
    ret
    .cfi_endproc
.LFE1:
    .size   is_letter2, .-is_letter2
    .globl  is_letter
    .type   is_letter, @function
is_letter:
.LFB2:
    .cfi_startproc
    pushl   %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    cmpl    $65, 8(%ebp)
    je  .L31
    cmpl    $66, 8(%ebp)
    je  .L31
    cmpl    $67, 8(%ebp)
    je  .L31
    cmpl    $68, 8(%ebp)
    je  .L31
    cmpl    $69, 8(%ebp)
    je  .L31
    cmpl    $70, 8(%ebp)
    je  .L31
    cmpl    $71, 8(%ebp)
    je  .L31
    cmpl    $72, 8(%ebp)
    je  .L31
    cmpl    $73, 8(%ebp)
    je  .L31
    cmpl    $74, 8(%ebp)
    je  .L31
    cmpl    $75, 8(%ebp)
    je  .L31
    cmpl    $76, 8(%ebp)
    je  .L31
    cmpl    $77, 8(%ebp)
    je  .L31
    cmpl    $78, 8(%ebp)
    je  .L31
    cmpl    $79, 8(%ebp)
    je  .L31
    cmpl    $80, 8(%ebp)
    je  .L31
    cmpl    $81, 8(%ebp)
    je  .L31
    cmpl    $82, 8(%ebp)
    je  .L31
    cmpl    $83, 8(%ebp)
    je  .L31
    cmpl    $84, 8(%ebp)
    je  .L31
    cmpl    $85, 8(%ebp)
    je  .L31
    cmpl    $86, 8(%ebp)
    je  .L31
    cmpl    $87, 8(%ebp)
    je  .L31
    cmpl    $88, 8(%ebp)
    je  .L31
    cmpl    $89, 8(%ebp)
    je  .L31
    cmpl    $90, 8(%ebp)
    jne .L32
.L31:
    movl    $1, %eax
    jmp .L33
.L32:
    movl    $0, %eax
.L33:
    popl    %ebp
    .cfi_def_cfa 4, 4
    .cfi_restore 5
    ret
    .cfi_endproc

履歴書では、同じプログラムです。

于 2013-05-20T20:24:58.723 に答える