【问题标题】:Why no strnspn() nor strncspn()?为什么没有 strnspn() 也没有 strncspn()?
【发布时间】:2014-03-26 22:22:53
【问题描述】:

有一个strnlen() 函数已被添加到各种高调库中已有一段时间,随后进入了POSIX-1:2008 等标准。 IIUC 的目的是避免主题字符串不是以 nul 结尾的问题。

但是,我没有看到类似的变体 strnspn()strncspn() 已经开发出来,尽管可能存在类似的潜在问题。是不是因为基础的strspn()strcspn()超出了很多C程序员的理解范围,所以应该没用或者不能用?

人们可能会注意到,在著名的“security-enhanced”(又名附件-K 或 M's-extension) 变体中,没有strcspn_s() 也没有@987654329 @ 要么...

【问题讨论】:

  • 我的意见是这些提议的函数应该被称为memspn()和memcspn()。使它们与 memcpy() 和 memcmp() 和 memmem() 保持一致。
  • @wildplasser:很有趣。尽管void* (+ count) 与s1 混合在一起,但我认为与s2 相对,这仍然是char*。此外,它对memspn() 更有意义,因为 s2 的终止 \0 可以被认为是 span 的一部分,但对于 memcspn() 则不太明显。
  • @wildplasser:mem* 函数在达到指定的字节数时终止,并且不特殊处理 '\0' 字符。 strn* 函数在达到指定字节数时终止 '\0' 终止符(嗯,主要是;strncpy 有点乱)。
  • 我知道。但我觉得需要此类功能的唯一可能情况是在搜索非 NUL 终止的内存段时,例如 mmap()ed 区域。在这种情况下,NUL 相对没有意义。 (并且总是可以事后检查)
  • "are beyond the understanding of many C programmers" - 当然......

标签: c cstring libc


【解决方案1】:

为什么特定函数没有出现在标准库中的答案通常归结为“没有足够多的人说他们需要它来证明强制每个实现都提供它是合理的,如果你确实需要它,你总是可以自己编写或使用已发布的众多版本之一。”

他们无法添加所有内容。在某些时候,会随意决定在哪里切断。

【讨论】:

    【解决方案2】:

    如果有人真的在寻找 C memspn()(我是,当我找到这个线程时),有 2 个版本,如果你是其中之一“goto 是邪恶的,我不会使用它 hurr durr”人:

    size_t memspn(const char *haystack, const size_t haystack_len, const char *mask, const size_t mask_len){
        size_t ret=0;
        for(;ret<haystack_len;++ret){
            const char c=haystack[ret];
            _Bool found=false;
            for(size_t ii=0;ii<mask_len;++ii){
                if(mask[ii]==c){
                    // this part can be optimized with a goto,
                    // in PHP i would use `continue 2;` here, which isn't supported by C
                    found=true;
                    break;
                }
            }
            if(!found){
                return ret;
            }
        }
        return ret;
    }
    
    

    对于我们其他人来说:

    size_t memspn(const char *haystack, const size_t haystack_len, const char *mask, const size_t mask_len){
        size_t ret=0;
        for(;ret<haystack_len;++ret){
            const char c=haystack[ret];
            for(size_t ii=0;ii<mask_len;++ii){
                if(mask[ii]==c){
                    // in PHP i would use `continue 2;` here, which isn't supported by C
                    goto continue2;
                }
            }
            return ret;
            continue2:;
        }
        return ret;
    }
    

    【讨论】:

    • 要将这个memspn() 用于strnspn() 需要小心使用以形成mask_len
    【解决方案3】:

    strnlen() 的存在使得在 strspn() 中使用字符串之前先对字符串进行完整性检查变得相对容易。

    strspn() 不如 strlen() 常用

    strspn() 接受两个 char* 参数,因为通常它只是需要长度保护的第一个字符串,所以第二个字符串是否应该或不应该有这个函数的长度限制的问题。

    【讨论】:

    • 我不同意第一点:如果确实需要避免主题字符串溢出,恕我直言strnlen() 不是正确答案:它只会给你一个有问题的迹象随着字符串的终止,但是由于没有直接的方法来对非\0 终止的字符串执行strspn() 的操作,因此您将结束自己对这种特殊情况的编码。而不是这样做,首先编写strnspn() 可能更容易,即当它“太远”时停止对字符串的搜索。其他两点有效,通过。
    • 是的,我认为这对于不打算以空终止的数组来说是正确的,尽管对于打算以空终止的字符串的鲁棒性,那么您可以轻松地执行以下操作: if ( strnlen(buffer, BUFFER_LEN) == BUFFER_LEN) 缓冲区[BUFFER_LEN-1]=0;
    猜你喜欢
    • 2014-09-15
    • 2019-05-11
    • 2012-09-14
    • 2019-01-20
    • 2017-09-03
    • 1970-01-01
    • 2014-06-25
    • 2023-03-04
    • 1970-01-01
    相关资源
    最近更新 更多