【问题标题】:How to calculate the length of a string in C efficiently?如何有效地计算C中字符串的长度?
【发布时间】:2011-01-05 10:44:54
【问题描述】:

如何在 C 中有效地(及时)计算字符串的长度?

我现在正在做:

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

但是与例如 strlen() 相比,它非常慢,有没有其他方法可以做到这一点?

谢谢。

编辑:我在一个独立的环境中工作,我不允许使用任何外部库,包括“string.h”。

【问题讨论】:

  • 那为什么不用strlen呢?或者这是一个练习?
  • 这不是一个练习,我工作的环境不允许我包含其他“libs”,包括“string.h”,所以我必须实现它并希望它在可维护的同时尽可能高效。
  • 您可能需要编辑原始帖子以说明您处于独立环境中。
  • 考虑到 std 库也可以在编译器优化激活的情况下进行编译,而您的代码则不能。
  • 这里有很好的答案,但请记住,这是微观优化,并不是所有的程序员都了解宏观优化的用途和重要性。下面是一个 40 倍加速的例子,代码看起来非常完美:stackoverflow.com/questions/926266/…

标签: c string performance


【解决方案1】:

计算字符串长度的基本 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);

【讨论】:

    【解决方案2】:

    我没有找到更好的:

    内联 size_t mystrlen(char *_)

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

    【讨论】:

      【解决方案3】:

      我遇到了同样的问题,我解决了。关键是for循环的第二个条件:

      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;
      }
      

      【讨论】:

        【解决方案4】:

        我不太确定你想做什么。

        您想要重写strlen 以使您的代码与标准 c-Library 兼容,或者您​​想要管理字符串。

        在第一种情况下,我认为你最好直接使用标准库。

        另一种情况很有趣:你应该看看 c++ 字符串类,它实现了特征策略(允许快速操作非常大的字符串)。

        【讨论】:

        • 这个问题的意思非常准确,并指出他不能使用标准包括,因为他处于独立环境中。
        【解决方案5】:

        上面的一些答案非常好,这是我的看法。 有一个关键字叫做“注册”

        #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

        来自第一个链接:

        这对于数组变量特别有用。数组变量 很容易与指针变量混淆。除非后面跟着 a [expr] 或 sizeof 它计算为第一个的地址 元素。如果您声明数组寄存器,所有这些用途都是 禁止;我们只访问单个元素或要求总数 尺寸。这样一个寄存器数组可能会更容易使用,就好像它 只是优化器的一组变量。无别名(访问 可能会出现相同的变量通过不同的指针)。

        因此,有时可能会出现性能波动。就个人而言,这是我最喜欢的实现之一,但 Sudhanshu 和 Andomar 也提供了一个很好的实现:)

        【讨论】:

          【解决方案6】:
          int max;
          max = sizeof(str);
          return (--max);
          

          【讨论】:

          • 这仅适用于 char 数组和 C 字符串文字。这不适用于指向字符串的指针。
          • 这个 WON'T WORK 带有字符串 variables
          【解决方案7】:

          在 i386 处理器上,libc 经常使用strlen 的超优化版本,通常用汇编语言编写。论文“String Length”解释了它们的工作原理。

          这是OpenBSD 的一个优化版本。 (他们也有portable version。)这是version for the GNU libc

          【讨论】:

            【解决方案8】:

            另一种加快字符计数的方法是使用矢量化!

            下面是一个关于如何处理 UTF8 编码字符串的示例:

            更快的 UTF-8 字符计数,

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

            【讨论】:

              【解决方案9】:

              C 字符串是intrinsically inefficient,使用 ASCIZ 约定有两个原因:

              • 标准 C 库使用它
              • 编译器将它用于文字字符串常量

              在这种情况下,第一个是学术性的,因为您没有使用标准库,第二个很容易通过创建函数或宏来克服,这些函数或宏提供从 C 字符串到更有效的约定(如 Pascal 字符串)的转换。关键是,如果您不使用 C 库,则不必成为 C 约定的奴隶。

              【讨论】:

              • ++ 你是对的,但有时我们会在所有错误的地方寻找循环。考虑到通常会使软件变慢的多种宏观方式,我还没有看到任何真正的代码,其中 strlen 的速度甚至在雷达上。
              • @Mike:完全同意。可能是过早的优化,但我链接的文章给出了几个在现实世界中至关重要的例子。帕斯卡字符串的 strlen() 函数既快速又具有确定性。
              • C 字符串在很多用例中效率低下,但在某些用例中优于帕斯卡字符串(例如substring = &amp;string[skipped];)。在其他地方跟踪字符串长度(不将其添加到字符串本身)可能比 pascal 字符串和 C 字符串更有效。
              【解决方案10】:

              看看GNU C library's strlen() source

              它使用了许多不明显的技巧来提高速度而不需要组装,包括:

              • 获取正确对齐的字符
              • 将字符串的对齐部分读入 int(或一些更大的数据类型),以一次读取多个字符
              • 使用位旋转技巧来检查嵌入在该字符块中的字符之一是否为零

              等等

              【讨论】:

              • 当前的 FreeBSD 使用类似的东西,也可以派上用场:freebsd.org/cgi/cvsweb.cgi/src/lib/libc/string/…
              • 你是什么意思“不下降到组装”?在 i386 上,它确实使用汇编(参见 Sudhanshu 的回复)。
              • Sudhanshu 的和我链接的不同。当为 x86 Sudhanshu 构建 glibc 时,肯定有可能使用(老实说,我不确定);但是,我指出的示例是直接的 C 代码,可以用作一些可能的优化示例。
              【解决方案11】:

              看一下标准libc中strlen的源码。标准库中的函数通常是高度优化的。看看here(汇编代码)——这是来自 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;
              }
              

              【讨论】:

              【解决方案12】:

              来自FreeBSD source code

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

              与您的代码相比,这可能很好地映射到汇编指令,这可以解释很大的性能差异。

              【讨论】:

              • 编译器应该能够相当有效地优化这一点,这意味着代码仍然可读,并且应该仍然运行得相当快。
              【解决方案13】:

              最简单的方法是致电strlen()。严重地。您的编译器和/或库供应商已经对其进行了优化,以尽可能快地适应您的架构。

              一种常见的优化是消除增加计数器的需要,并根据指针计算长度:

              size_t my_strlen(const char *s)
              {
                const char *anchor = s;
              
                while(*s)
                 s++;
              
                return s - anchor;
              }
              

              【讨论】:

                【解决方案14】:

                strlen()。很可能,如果有人找到了更好、更快的泛型方法,strlen 就会被替换掉。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2017-12-05
                  • 2018-11-05
                  • 2018-01-30
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多