Preamble: Everything I say depends a bit on the specific compiler and how it implements implicit integer type promotions. I'm talking about ANSI C8= 9, assuming an int of 2 bytes (if the int is longer, like 4 bytes, it works similar). Buehler, Martin wrote: > Why does a one's complement of an 'unsigned char' not return an 'unsign= ed > char'?=20 Short answer: because all operations on types smaller than int are done a= s ints. The results are then cast back when assigning to variables, but not for subsequent operations that are not assignments. Long answer: > unsigned char a,b;=20 >=20 > a =3D 0x03; b =3D ~a; //b =3D 0xfc=20 "b =3D ~a;" can also be written as { int _internal_temp =3D a; _internal_temp =3D ~_internal_temp; b =3D (unsigned char)_internal_temp; } > if (a =3D=3D ~b) {/* true */} else {/* false */}=20 >=20 > according to my understanding, this should always evaluate to 'true', a= s > =B4~b' is 0x03. but it does not! it always evaluates to 'false'. a bitw= ise > one's complement seems to return an undefined width, instead of a 8 bit > value (unsigned char).=20 The expression (a =3D=3D ~b) gets evaluated like this: { int _internal_temp_b =3D b; // high byte is 0, because b is unsigned _internal_temp_b =3D ~_internal_temp_b; // high byte is now 0xff int _internal_temp_a =3D a; // high byte is 0, because a is unsigned return (_internal_temp_a =3D=3D _internal_temp_b); } The two internal temp variables are not the same. Their high byte is different. > i found several workarounds to evaluate to true:=20 Now applying the above to your workarounds: > 1) signed char a,b; (instead of unsigned) -> i really don't like signed > char for logic operations=20 Declaring a and b as signed changes the handling of the high bytes, becau= se the sign bit gets now extended into the high byte. The expression (a =3D=3D= ~b) gets now evaluated like this: { int _internal_temp_b =3D b; // high byte is 0xff, because b is signed a= nd negative _internal_temp_b =3D ~_internal_temp_b; // high byte is now 0 int _internal_temp_a =3D a; // high byte is 0, because a is signed and positive return (_internal_temp_a =3D=3D _internal_temp_b); } This "works", but only because the values are as they are (a positive, b negative). The "working" depends on the high bits (the sign) of a and b. Dangerous and not recommended. > 2) if (a =3D=3D (unsigned char)~b) {/* true */} -> seems to be the mos= t > efficient way=20 This not only works, but is also the cleaner way. After b gets implicitly promoted to int for the ~ operation, you cast it back to the original typ= e (unsigned char) before the next operation (=3D=3D). The result of this ca= st is that you are comparing two unsigned chars, which get again promoted to in= t for =3D=3D, but in the same way (with the high byte being 0 for both). > 3) if (a =3D=3D (~b & 0xff)) {/* true */} -> requires more memory=20 That is similar to 2), but less clean, in that it only clears the high by= te of the int resulting from the expression ~b, whereas 2) also shows what's really going on. Most optimizing compilers should generate the same code for 2) and 3), though. (BTW, since a byte is such a common type for embedded programming, it is probably convenient to declare a type for it, instead of typing the inconvenient "unsigned char" so often. I use an include file where I declare the types u8, i8, u16, i16, u32, i32 -- which then are always wha= t they seem to say they are, independently of the particular compiler. :) For more information, look for implicit conversions in a C standard and i= n your compiler's manual. Also note that many 8 bit compilers implement this (types and type promotions) not 100% standard conform, so the results may vary depending = on the compiler. But in any case, your results can be explained by the standard. Gerhard --=20 http://www.piclist.com PIC/SX FAQ & list archive View/change your membership options at http://mailman.mit.edu/mailman/listinfo/piclist