Der Schein trügt

Letzens habe ich ein interessantes Codefragment in einer Vorlesung gesehen:

unsigned char x;
 
x = ~0xFF;
 
if(x == ~0xFF) {
	// should go there
} else {
	// but is ending up here
}

Wir landen hier eigentlich unerwartet im else-Zweig, aber warum?

Dabei muss man wissen, dass 0xFF z.B. bei einem 16-Bit-µC im Regelfall auch in ein 16-Bit-Register geladen wird, wenn intern (im Prozessor) damit gearbeitet wird, z.B. bei einer Addition.

Bei der Zuweisung wird 0xFF im Prozessorregister zu 0x00FF expandiert. Durch die Negation (~) ändert sich der Registerinhalt in 0xFF00. Das ist alles noch kein Problem, da durch den unsigned char nur die unteren 8 Bit berücksichtigt werden und somit 0x00 in x abgelegt wird.

Beim Vergleich wird dann 0x00 im Prozessorregister zu 0x0000 und wird somit mit 0xFF00 (0xFF -> 0x00FF -> (~) -> 0xFF00) verglichen. Und dieser Vergleich ergibt dann FALSE, weshalb wir dann auch im else-Zweig enden.