Un AND bit a bit recupera il bit pattern dall'altro operando. Significato, 10101 & 11111 = 10101
. Se il risultato di questo bit AND è 0, allora sappiamo che l'altro operando era 0. Un risultato di 0 quando ANDing di un singolo byte con 0xFF
(uno) indicherà un byte NULL.
Il codice stesso controlla ogni byte dell'array char in partizioni a quattro byte. NOTA: Questo codice non è portatile; su un'altra macchina o compilatore, un int unsigned potrebbe essere superiore a 4 byte. Probabilmente sarebbe meglio usare il tipo di dati uint32_t
per garantire numeri interi senza segno a 32 bit.
La prima cosa da notare è che su una macchina little-endian, i byte che costituiscono l'array di caratteri verranno letti in un tipo di dati senza segno in ordine inverso; vale a dire, se i quattro byte all'indirizzo corrente corrispondono al modello di bit corrispondente a abcd
, la variabile senza segno conterrà il modello di bit corrispondente a dcba
.
Il secondo è che una costante di numero esadecimale in C restituisce un numero int-sized con i byte specificati all'estremità inferiore del modello di bit. Significato, 0xFF
è in realtà 0x000000FF
durante la compilazione con 4 byte int. 0xFF00
è 0x0000FF00
. E così via.
Quindi il programma cerca fondamentalmente il carattere NULL nelle quattro posizioni possibili. Se non c'è alcun carattere NULL nella partizione corrente, avanza al successivo slot a quattro byte.
Prendere il char array abcdef
per un esempio. In C, le costanti di stringa avranno sempre terminatori nulli alla fine, quindi c'è un byte 0x00
alla fine di quella stringa.
Funzionerà come segue:
Leggi "abcd" in unsigned int x:
x: 0x64636261 [ASCII representations for "dcba"]
Controllare ogni byte per un terminatore null:
0x64636261
& 0x000000FF
0x00000061 != 0,
0x64636261
& 0x0000FF00
0x00006200 != 0,
e verificare gli altri due posizioni; non ci sono terminatori nulli in questa partizione a 4 byte, quindi vai alla partizione successiva.
Leggi "ef" in unsigned int x:
x: 0xBF006665 [ASCII representations for "fe"]
Nota byte 0xBF; questo è oltre la lunghezza della stringa, quindi stiamo leggendo nella spazzatura dallo stack di runtime. Potrebbe essere qualsiasi cosa. Su una macchina che non consente accessi non allineati, questo si bloccherà se la memoria dopo la stringa non è allineata a 1 byte. Se nella stringa ci fosse solo un carattere, dovremmo leggere due byte extra, quindi l'allineamento della memoria adiacente al char array dovrebbe essere allineato a 2 byte.
Controllare ogni byte per un terminatore null:
0xBF006665
& 0x000000FF
0x00000065 != 0,
0xBF006665
& 0x0000FF00
0x00006600 != 0,
0xBF006665
& 0x00FF0000
0x00000000 == 0 !!!
così torniamo len + 2
; len
era 4 poiché lo abbiamo incrementato una volta per 4, quindi restituiamo 6, che è effettivamente la lunghezza della stringa.
Commercia un comportamento indefinito per una velocità molto discutibile (è molto probabilmente anche più lento). E non è conforme allo standard, perché restituisce 'int' invece di' size_t' – Olaf
Sì, questo non causa problemi se il tipo int diventa più grande di 4 byte o se la macchina non è little-endian? –
@MillieSmith: Questo è il problema minimo, poiché la maggior parte dei sistemi a 64 bit è I32LP64 (POSIX). Il problema è l'accesso non allineato, l'endianess (come hai affermato). Anche se gli accessi non allineati sono consentiti sulla piattaforma, possono essere molto più lenti degli accessi allineati. Per non parlare della maschera multipla e delle operazioni condizionali. – Olaf