3

There is a strnlen() function which has been added for some time to various high-profile libraries, and subsequently made its way into standards like POSIX-1:2008. IIUC its purpose is to avoid problems when the subject string is not nul-terminated.

However, I do not see the similar variants strnspn() or strncspn() to have been developed, despite that similar potential problems might be alleged. Is it just because the base strspn() and strcspn() are beyond the understanding of many C programmers, hence supposed to be unused or unusable?

One may notice that in the (in)famous "security-enhanced" (a.k.a. annex-K or M's-extension) variants of the string functions , there are no strcspn_s() nor strspn_s() either...

AntoineL
  • 888
  • 4
  • 25
  • 1
    My opinion is that these proposed functions should be called memspn() and memcspn(). To keep them in line with memcpy() and memcmp() and memmem(). – wildplasser Feb 24 '14 at 23:47
  • @wildplasser: Interesting. Despite the mix of `void*` (+ count) for `s1`, to be opposed with `s2` which would still be `char*`, I think. Also, it makes more sense for `memspn()` since the terminating `\0` of s2 can be considered part of the *span*, but it is less evident for `memcspn()`. – AntoineL Feb 25 '14 at 00:08
  • 2
    @wildplasser: The `mem*` functions terminate when they reach the specified number of bytes, and don't treat a `'\0'` character specially. The `strn*` functions terminate when they reach the specified number of bytes *or* a `'\0'` terminator (well, mostly; [`strncpy`](http://the-flat-trantor-society.blogspot.com/2013/12/where-should-control-key-be.html) is a bit of a mess). – Keith Thompson Feb 25 '14 at 00:15
  • I know that. But the only possible cases where I ever felt the need for such functions was when searching not NUL-terminated stretches of memory, eg mmap()ed areas. The NUL is relatively meaningless in that case. (and can always be checked post-hoc) – wildplasser Feb 26 '14 at 10:00
  • **`"are beyond the understanding of many C programmers"`** - sure ...... – 0___________ Jul 09 '20 at 15:53

3 Answers3

3

The answer to why specific functions don't appear in a standard library usually boils down "there weren't enough people who said they needed it to justify forcing every implementation to provide it, and if you do need it you can always write it yourself or use one of the many versions which has been published."

They can't add everything. At some point, an arbitrary decision gets made about where to cut things off.

keshlam
  • 7,931
  • 2
  • 19
  • 33
3

in case someone is actually looking for a C memspn() (i was, when i found this thread), got 2 versions, if you're one of those "goto is evil i won't use it hurr durr" people:

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

and for the rest of us:

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;
}
hanshenrik
  • 19,904
  • 4
  • 43
  • 89
0

The presence of strnlen() makes it relatively easy to first sanity-check a string before using it in strspn().

strspn() is less commonly used than strlen()

strspn() takes two char* arguments, and since normally it would just be the first string that would need length protection, there is the question of whether the second should or shouldn't have a length limit for this function.

sj0h
  • 902
  • 4
  • 4
  • 1
    I disagree with the first point: if there is a genuine need to avoid overrun on the subject string, IMHO `strnlen()` is not the correct answer: it only will give you the indication there is a problem with the termination of the string, but since there is no straightforward way to perform the action of `strspn()` on a non-`\0`-terminated string, you'll end coding yourself this peculiar case. Rather than doing that, it is probably easier to code `strnspn()` in the first place, i.e. stopping the search through the string when it goes "too far". The other two points are valid, through. – AntoineL Feb 25 '14 at 09:44
  • Yes, I think that's true for arrays that are not intended to be null-terminated, though for robustness of strings that are meant to be null-terminated, then you can easily do something like: if (strnlen(buffer, BUFFER_LEN) == BUFFER_LEN) buffer[BUFFER_LEN-1]=0; – sj0h Feb 25 '14 at 23:18