web-dev-qa-db-ja.com

Cで文字列の長さを効率的に計算する方法は?

Cで文字列の長さを効率的に(時間内に)計算する方法は?

今私はやっています:

int calculate_length(char *string) {
    int length = 0;
    while (string[length] != '\0') {
        length++;
    }
    return length;
}

しかし、たとえばstrlen()に比べて非常に遅いです。それを行う他の方法はありますか?

ありがとう。

編集:私は独立した環境で作業しています。「string.h」を含む外部ライブラリを使用することはできません。

22
Carla Álvarez

FreeBSDソースコード から:

size_t
strlen(const char *str)
{
    const char *s;
    for (s = str; *s; ++s);
    return(s - str);
}

コードと比較して、これはおそらくアセンブラー命令に非常にうまく対応し、パフォーマンスの大きな違いを説明できます。

44
Andomar

標準libcのstrlenのソースコードを見てください。標準ライブラリの関数は、一般的に高度に最適化されています。それをチェックしてください ここ (アセンブリでコーディング)-これはGNU libcからのものです。

size_t
DEFUN(strlen, (str), CONST char *str)
{
  int cnt;

  asm("cld\n"                   /* Search forward.  */
      /* Some old versions of gas need `repne' instead of `repnz'.  */
      "repnz\n"                 /* Look for a zero byte.  */
      "scasb" /* %0, %1, %3 */ :
      "=c" (cnt) : "D" (str), "0" (-1), "a" (0));

  return -2 - cnt;
}
9
Sudhanshu

strlen()。オッズは、誰かがより良い、より高速なジェネリックメソッドを見つけた場合、strlenはそれに置き換えられたはずです。

9
aib

GNU Cライブラリのstrlen() source を見てください。

それはアセンブリを落とさずにスピードを上げるために以下のようないくつかの自明ではないトリックを使用します:

  • 適切に配置されたキャラクターに到達する
  • 一度にいくつかの文字を読み取るために、文字列のそれらの整列された部分をint(またはより大きなデータ型)に読み取る
  • 文字のブロックに埋め込まれた文字の1つがゼロであるかどうかを確認するためにビットをいじるトリックを使用する

等.

6
Michael Burr

最も簡単な方法は、strlen()を呼び出すことです。真剣に。コンパイラやライブラリベンダーによってすでに最適化されており、アーキテクチャに対して可能な限り高速になります。

一般的な最適化の1つは、カウンターを増やす必要をなくし、ポインターから長さを計算することです。

size_t my_strlen(const char *s)
{
  const char *anchor = s;

  while(*s)
   s++;

  return s - anchor;
}
3
unwind

C文字列は 本質的に非効率的 です。ASCIZ規則を使用する理由は2つあります。

  • 標準Cライブラリはそれを使用します
  • コンパイラはリテラル文字列定数にそれを使用します

標準ライブラリを使用していないため、これらの1つ目はこの場合アカデミックです。2つ目は、C文字列からPascal文字列などのより効率的な規則への変換を提供する関数またはマクロを作成することで簡単に克服できます。重要なのは、Cライブラリを使用していない場合は、C規約のスレーブである必要はないということです。

3
Clifford

文字カウントを高速化するさらに別の方法は、ベクトル化を使用することです!

UTF8エンコードされた文字列に関してこれを行う方法の例を次に示します。

さらに高速なUTF-8文字カウント、

http://www.daemonology.net/blog/2008-06-05-faster-utf8-strlen.html

2
qbitty

上記の答えのいくつかは非常に良いです、そしてこれは私の見解です。 「登録」というキーワードがあります

#include <stdio.h>
size_t strlenNew(char *s);

int main(int argc, char* argv[])
{
    printf("Size of \"Hello World\" is ::\t%d",strlenNew("Hello World"));
    return 0;
}

size_t strlenNew(char *s)
{
    register int i=0;
    while(s[i]!='\0') i++;
    return i;
}

ここをお読みください: http://gustedt.wordpress.com/2010/08/17/a-common-misconsception-the-register-keyword/ および http://msdn.Microsoft .com/en-us/library/482s4fy9(v = vs.80).aspx

最初のリンクから:

これは、配列変数に特に役立ちます。配列変数は、ポインター変数と混同されやすいです。 [expr]またはsizeofが後に続かない限り、最初の要素のアドレスに評価されます。配列レジスターを宣言すると、これらの使用はすべて禁止されます。個々の要素にアクセスするか、合計サイズを要求するだけです。このようなレジスタ配列は、オプティマイザによる変数のセットであるかのように、はるかに簡単に使用できます。エイリアス(異なるポインタを介して同じ変数にアクセスする)は発生しません。

そのため、パフォーマンスが変動する場合があります。個人的には、これは私のお気に入りの実装の1つですが、SudhanshuとAndomarも優れた実装を提供しています:)

同じ問題があり、解決しました。重要なのは、forループの2番目の条件です。

int longitud(char cad[]){

    int i, cont;

    cont = 0;

    for(i = 0; i < 30 && cad[i] != '\0'; i++){
        if(cad[i] != '\0'){
            if(cad[i] != ' '){
                cont++;
            }
        }
    }
    cont--;
    return cont;
}
0
Victor26567

文字列長を計算する基本的なCプログラム

#include <stdio.h>

/**
* Method to calculate string length.
* Returns -1 in case of null pointer, else return string length.
**/
int length(char *str) {

    int i = -1;
    // Check for NULL pointer, then return i = -1;
    if(str == NULL) return i;

    // Iterate till the empty character.
    while (str[++i] != '\0');
    return i;  // Return string length.
}

int main (int argc, char **argv) {

    int len = 0;
    char abc[] = "hello";
    len = length(abc);
    printf("%d", len);  
    return 0;
}

注:より適切な方法として、メモリリークが発生しないように、常に配列サイズを関数に渡す必要があります。たとえば、**メソッドのプロトタイプは次のようにする必要があります*:*

/**
* @desc calculate the length of str.
* @param1 *str pointer to base address of char array.
* @param2 size = capacity of str to hold characters.
* @return int -1 in case of NULL, else return string length.
**/
int length (char *str, int size);
0
Rahul Raina

私はより良いとは思いませんでした:

インラインsize_t mystrlen(char * _)

  { return ((_ == NULL) ? (_[0] != '\0')) ? 0 : (1 + mystrlen(_ + 1)); }
0
blueperfect

I386プロセッサでは、libcは、多くの場合、アセンブリ言語で書かれたstrlenの超最適化バージョンを使用します。 「 String Length 」という論文は、それらがどのように機能するかを説明しています。

これが OpenBSD に最適化されたバージョンです。 (これらには ポータブルバージョン もあります。)ここに GNU libc のバージョン)があります。

0
bortzmeyer