Can someone explain to me in layman's terms how this function works?
https://codebrowser.dev/glibc/glibc/string/strlen.c.html
Thank you.
Can someone explain to me in layman's terms how this function works?
https://codebrowser.dev/glibc/glibc/string/strlen.c.html
Thank you.
It iterates over the characters of the string, and counts them, until it finds a 0. Then it returns the counted number of characters that are not 0.
Note that a literal string like “abc”
generates 4 bytes {'a', ‘b', ‘c’, 0}
, so strlen
works as expected on such values
Thus
strlen("") -> returns 0
char x[4] = {'a', 'b', 'c', o}; // Make your own 0-terminated string.
strlenx) -> returns 3
That version is using some old bitwise math tricks to process the string faster.
If it has at least 4 or 8 values remaining it uses a bitwise counting trick to check all 4 or 8 bytes for zeros. The algorithm is more complex than a simple loop testing against zero, but because of CPU architecture the processing is faster despite more complexity.
First it sets the “magic” bit pattern for 32-bit or 64-bit test, for both the high bit and low bit.
The test is: ((longword - lomagic) & ~longword & himagic) != 0
For each 8-bit value, it subtracts 1, then AND compares the result of NOT the value AND the high bit to ensure something is set.
Let's try to use “something” as the value 1, although anything works, and as zero or the null character.
Walking through it: 1 - the low bit is zero. NOT 1 is 254. The high bit is 128. 0 AND 254 is zero, AND 128 is zero. Getting a zero is expected, it means the bits had something in it.
Since it was done on 4 or 8 at once, zero means all 4 or 8 had some value in the string and it should keep scanning for the end, skipping 4 or 8 bytes instead of 1.
Walking through it with zero: 0 - the low bit is -1, which is going to either flip the sign of the 64-bit value or the high bit of the next value down, or flip a bunch of bits in the middle as a value has to trickle down. We'll take the path that it is now 255, NOT 0 is 255. AND the results, 255 AND 255 is 255, AND with 128 is 128. The result wasn't zero, so we know the test value was a zero.
If it had set the -1 on the next value's high bit instead of flipping the value, we'll reuse 1… The results of the subtraction makes the 1 value get the negative carry-over so the first subtraction subexpression is 128 instead of zero. NOT 1 is still 254. 128 AND 254 is 128, AND 128 for the high bit is still 128, so again we know a zero was present.
And in the case of it needing to pull bits from much higher, they are 8 bits of zero at least. Just like subtracting 1 from 20000000000 can't help but set a bunch of values to 9's, pulling the value down from one of the other values in the 4-char or 8-char chain will similarly flip a bunch of bits. There are some pathological cases (an exercise to the reader) where the combination of values will happen to cancel out so when they get a zero result they switch back to the one-at-a-time approach to find the stopping point, with the unlikely extra option that it was a false positive and resuming the fast scan in that case.
In any event, they scan the string 4 or 8 letters at a time as long as they can, then one at a time, until they find the zero value.
The small amount of math to test all the values at once is slightly faster, so we'll take the performance gain in a frequently called function.