【问题标题】:C: Custom strlen() library functionC: 自定义 strlen() 库函数
【发布时间】:2017-01-19 05:21:02
【问题描述】:

我创建了我的strlen() 函数版本。

unsigned int my_strlen(char *p)
{
    unsigned int i = 0;

    while(*p!='\0')
    {
        i++;
        p++;
    }

    return i;
}

每次运行时它都会给我正确的输出。但是我的同事说这段代码可能会在字符长度大于1 byte 的系统上导致问题。是这样吗??

于是他们修改了代码如下:

unsigned int my_strlen(char *p)
{
    unsigned int i = 0;
    char *start = p;

    while(*p!='\0')
    {
        i++;
        p++;
    }

    return p - start;
}

我一直认为 C 中的字符是 1 个字节长。

是前者的sn-p优于后者还是相反??

【问题讨论】:

  • 您的同事可能正在考虑使用 UTF 字符集(例如),您的字符超过 8 位(例如,大于八位字节)。您的第二个实现有一个未使用的变量,因此更糟。
  • @markw 由于 UTF 字符占用 2 个字节,所以在这种情况下 char 是 2 个字节长?
  • 指针算法的工作方式与数组索引相同。在这两种情况下,编译器都知道数据大小。所以p++被调整为指向下一个数据项,不管它的大小。您的朋友保留函数参数的副本并递增p 也是错误的,应该反过来 - 修改参数的副本。
  • @Cody 根据我的经验,UTF 通常需要使用所谓的“宽字符”,它包含多个字符。根据您的平台,宽字符可能与字符大小相同。
  • i 乘以 sizeof(char)(始终为 1)是不必要但无害的。对于任何其他类型,您都希望这样做。

标签: c types char sizeof strlen


【解决方案1】:

strlen 函数使用for:

size_t my_strlen(const char *s) {

    size_t n;

    for (n = 0; *s; s++)
        n++;
    return n;
}

或者:

size_t n;

for (n = 0; *s != '\0'; s++)
    n++;
return n;

或者:

size_t n;

for (n = 0; *(s++); )
    n++;
return n;

或者:

size_t n;

for (n = 0; *s; n++)
    s++;
return n;

或者:

size_t n = 0;
int i;

for (i = 0; s[i]; i++)
    n++;
return n;

【讨论】:

    【解决方案2】:

    OP 发布“字符 的长度大于 1 字节”,而不是 char。当将一个字符限制为仅charsigned charunsigned char 时,OP 是正确的。这 3 个 总是 的大小为 1。

    OP 的同事可能并非都以这种限制性的方式思考。 C规范有许多字符类型:单字节字符多字节字符扩展字符宽字符,而不是全部 1 个字节。

    修改后的代码有弱点。与“字符长度大于 1 个字节”有关是不明智的。此外,i++; 毫无意义。 unsigned 的返回类型可能不够。对既不太宽也不太窄的无符号类型使用size_t

    // simplify
    size_t my_strlen2(const char *p) {
        const char *start = p;
        while(*p) p++;
        return (size_t) (p - start);
    }
    

    是前者的sn-p优于后者还是相反??

    都不返回不会溢出的类型。

    【讨论】:

      【解决方案3】:

      就指针算术而言,只要您处理指针和指针算术始终坚持数据类型,它不会在 char 为 2 个字节的平台上为您提供不同的结果。 这是另一种查找字符串 len 的方法,它不使用指针 airthmetic-

      int len  = -1;
      while(p[++len] != '\0');
      return len;
      

      【讨论】:

      • @BLUEPIXY 你能捍卫你的主张吗?
      • while(p[len] != '\0') { len++; }
      • "...在 char 为 2 字节长的平台上..." 根据定义,没有这样的平台。
      • @Keith Thompson 我的意思是 UTF 字符集
      • 如果您的意思是 UTF-8、UTF-16 或 UTF-32,它们是 Unicode 字符集的表示;它们本身不是字符集。在任何情况下,sizeof (char) == 1根据定义。 (一个字节中的位数可能(很少)变化。)
      【解决方案4】:

      虽然其他人回答了你关于字符大小的问题,但你的版本仍然不正确。

      当前的标准 (ISO/IEC 9899:2011) 在这里简短而准确:

      7.24.6.3 strlen 函数

      概要

          #include <string.h>`<br>
          size_t strlen(const char *s);
      

      说明

      2strlen函数计算s指向的字符串的长度。

      退货

      3 strlen 函数返回前面的字符数 终止空字符。

      所以一个完全兼容的函数应该是

      size_t stringlength(const char *s){
        size_t i = 0;
        while(s && *s != '\0'){
            s++;
            i++;
        }
        return i;
      }
      

      主要区别在于它检查输入(可以是NULL,但例如:glibc 的strlen segfaults。如果你想让它出现segfault,请在循环中剥离s == NULL 的测试。Segfaulting 可能是更好的选择,否则你会得到我们喜欢称之为“Heisenbugs”的那种错误。当你看到它们并且它们的波形崩溃时往往会消失的错误)并使用size_t作为输出。

      Glibc 版本在可能的情况下一次处理多个字节——不知道这样的优化是否有用。

      如果你想要 wsclen() 的等价物,你可以这样做:

      #include <wchar.h>
      size_t wstringlength(const wchar_t *s){
        size_t i = 0;
        while(s[i] != L'\0'){
            i++;
        }
        return i;
      }
      

      计算多字节字符(mbrlen() 仅检查一个字符,但您可以使用 mbrtowc())非常复杂,超出了这篇短文的范围。

      【讨论】:

      • 测试s == NULL 不需要符合 C 标准库。如果使用,建议不要将其作为 while() 循环的一部分。
      【解决方案5】:

      在 C 中保证sizeof(char) 是 1,所以你是对的。

      要添加一些真实性,请直接引用 C11,第 §6.5.3.4 章,sizeof_Alignof 运算符

      sizeof 应用于类型为 charunsigned charsigned char,(或其合格版本)结果为 1。[....]

      也就是说,指针算术尊重数据类型,所以第二种方法对于预期要做的事情没有任何意义。两种情况,你都在p上操作,也就是char*,所以效果是一样的。

      【讨论】:

      • 所以两个版本是等价的?
      • @Cody 我想说,第一个更好。
      • UTF 字符呢?它们占用超过 1 个字节吗?
      • @Cody 是的,它们占用超过 1 个字节,但这不是您在 C 中处理 UTF 的方式。通常我们使用其他一些库 (qt) 来处理它们。
      • @Cody 好吧,实际标准不是免费的,你可以检查一个近乎完美的副本here
      【解决方案6】:

      当您使用p++ 时,您的指针会增加sizeof(char)。因此,sizeof(char) 是什么无关紧要,即使它在不同机器之间是可变的。你的同事错了。

      注意:如果您想计算字节数,而不是字符数,那么您的同事可能是正确的(如果不能保证 char 是 1 个字节,但它是)。如果你要数字符,那你的同事就完全错了。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-08-14
        • 1970-01-01
        • 1970-01-01
        • 2012-09-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多