Primeiramente, a função strlen
deve ser usada apenas com strings, nunca com arrays de outros tipos. Em segundo lugar, a forma como é implementada não é muito óbvia, pois a implementação ingênua é demasiadamente lenta. Segue o código adaptado da implementação da glibc (usada pelo GCC).
#define CAST(type, value) ((type) (value))
#define UNTIL_ALIGNED(x) ( (CAST(unsigned long, x) & (sizeof(uint32_t) - 1)) ) != 0
size_t strlen(const char *str) {
const char *char_ptr;
const uint32_t *longword_ptr;
// Handle the first few characters by reading one character at a time.
// Do this until CHAR_PTR is aligned on a longword boundary.
for (char_ptr = str; UNTIL_ALIGNED(char_ptr); char_ptr++)
if (*char_ptr == '\0')
return char_ptr - str;
longword_ptr = (uint32_t*) char_ptr;
// Bits 31, 24, 16, and 8 of this number are zero. Call these bits
// the "holes." Note that there is a hole just to the left of
// each byte, with an extra at the end:
// bits: 01111110 11111110 11111110 11111111
// bytes: AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD
// The 1-bits make sure that carries propagate to the next 0-bit.
// The 0-bits provide holes for carries to fall into.
const uint32_t himagic = 0x80808080L;
const uint32_t lomagic = 0x01010101L;
// Instead of the traditional loop which tests each character,
// we will test a longword at a time. The tricky part is testing
// if *any of the four* bytes in the longword in question are zero.
for (;;) {
uint32_t longword = *longword_ptr++;
if (((longword - lomagic) & himagic) != 0) {
// Which of the bytes was the zero? If none of them were, it was
// a misfire; continue the search.
const char *cp = (const char *) (longword_ptr - 1);
if (cp[0] == 0)
return cp - str;
else if (cp[1] == 0)
return cp - str + 1;
else if (cp[2] == 0)
return cp - str + 2;
else if (cp[3] == 0)
return cp - str + 3;
}
}
}
Para entender como esta implementação funciona, e o porquê do seu problema, é preciso entender sobre numeração binária e arquitetura de computadores, algo que não é possível endereçar em um comentário breve.
Em segundo lugar, os números estranhos que você recebeu ao mudar o valor da guarda para 10 se deve ao fato de que arrays são blocos de memória em posições adjacentes acessados via aritmética de ponteiros. Você está acessando posições de memória que não pertencem ao array e que não foram inicializadas, e portanto contêm lixo (valores residuais aleatórios). Neste caso, em que você está apenas lendo os danos potenciais são menores, contudo, este é um erro grave, que incorre em comportamento indefinido, o que significa que em certas circunstâncias pode fazer o programa acabar prematuramente, em outras pode corromper a memória e gerar resultados inesperados.