"Fast strlen" in C using scalar bithacks I've translated an implementation of strlen in x86 assembly to C and added alignment checking:

#include &lt;strings.h&gt;
#include &lt;string.h&gt;
#include &lt;stdint.h&gt;

#define NOT_HIGH_MASK 0x080808080
#define HIGH_MASK 0x7f7f7f7f
#define LOW_MASK 0x01010101
#define mul4(x) ((x) &lt;&lt; 2)
#define div8(x) ((x) &gt;&gt; 3)

size_t strlen(const char *str)
{
    const char *cptr = str;
    uint32_t i, *s;
    size_t ctr = 0;

    /* Satisfy alignment requirements */
    while((uintptr_t)cptr &amp; (sizeof(uint32_t)-1))
    {
        if(!*cptr)
            return cptr - str;
        cptr++;
    }

    s = (uint32_t *)cptr;

    do {
        i = s[ctr];
        /* Mask off high bit */
        i &amp;= HIGH_MASK;
        /* subtract 0x01 from each byte,
           giving a set high bit if it
           was zero */
        i -= LOW_MASK;
        ctr++;
            /* Test for the set high bit
               and if it is found exit */
    } while(!(i &amp;= NOT_HIGH_MASK));

    /* Find the first high bit set and
       create the corresponding byte index */
    i = div8(ffs(i));
    /* Remove the counter increment from the
       loop and multiply it by 4 to find the
       rest of the byte index */
    ctr = mul4(ctr - 1);

    /* Return the combined byte index with 1
       removed so it doesn't include the null
       terminator itself */
    return i + ctr - 1;
}


I'm looking for general critique, but I'd also like additional information in these areas:


Portability. Is this portable? Will it work on all common platforms (x86, arm, etc.) and possibly some uncommon ones?
Comments. The comments I've put here seem to already document the code well enough, but is there any additional information I could add?
Hidden Bugs. This definitely works (and has a noticeable improvement in speed), but are there any hidden bugs relating to alignment requirements or otherwise (such as extended ASCII)? For context, this is part of a standard C/POSIX library implementation.


I might note that I'm relying on my header to use the builtin version of ffs. This may be an issue on non-GNU compilers.

If a GCC-compatible compiler (gcc, clang, icc, etc.) is detected during the build process, the flags -std=gnu99 -O2 are appended to the build flags.
Bug

strlen("\x80\x80\x80\x80\x80\x80\x80") does not return the expected 7.  The do loop does not distinguish between '\0' and '\x80'.

strlen("\x80\x80\x80") returns 0, 1, 2  or 3 depending on alignment.

These render  the function broken.

Why int32_t?

Certainly int32_t* marches down the sting at a 4x clip rather than a plodding char *.  Yet for a 16-bit int machine, int32_t* may be slower.  For a 64-bit machine, int64_t* could even be faster.   I'd expect a unsigned * to work fast or even fastest.  I guess that is why strlen() is a library function - each implementation is expected to use its own optimal approach.

Minor: Clearly use unsigned mask constants

With bit masking, shifts and subtraction, using unsigned math has less review concerns.

0x01010101 --> 0x01010101u.

Portability

while(... &amp; (sizeof(uint32_t)-1)) is a reasonable alignment test but not a specified correct one.  Conversion of a pointer to an integer need not follow the usual linear expectations.  I do not know of any implementation where this will not work, but it is not C specified.

Notes:
uint32_t is an optional type.  A unicorn platform may not have it defined.
uintptr_t is also an optional type.

Could use something like 

#include &lt;stdint.h&gt;
#ifndef UINTPTR_MAX
  #error "You are kidding me? An implementation without uintptr_t!" 
#endif


Comment nit

Mask off high bit should be "Mask off high bits" or "Mask off each byte high bit", ...

/* Mask off high bit */
i &amp;= HIGH_MASK;