Exact match. Not showing close matches.
PICList
Thread
'[PIC] C-Compiler: One's complement of unsigned cha'
2005\12\02@043433
by
Buehler, Martin
|
Why does a one's complement of an 'unsigned char' not return an 'unsigned char'?
example:
unsigned char a,b;
a = 0x03;
b = ~a; //b = 0xfc
if (a == ~b) {/* true */}
else {/* false */}
according to my understanding, this should always evaluate to 'true', as ´~b' is 0x03.
but it does not! it always evaluates to 'false'.
a bitwise one's complement seems to return an undefined width, instead of a 8 bit value (unsigned char).
i found several workarounds to evaluate to true:
1) signed char a,b; (instead of unsigned) -> i really don't like signed char for logic operations
2) if (a == (unsigned char)~b) {/* true */} -> seems to be the most efficient way
3) if (a == (~b & 0xff)) {/* true */} -> requires more memory
although i found a workaround for the problem, i do not really understand why it does not automatically reduce the with to unsigned char, if only unsigned chars are involved.
i searche through my c reference book, but found nothing on this.
anyone knows?
thanx!
tino
2005\12\02@055039
by
sergio masci
|
part 1 1449 bytes content-type:TEXT/PLAIN; charset=UTF-8 (decoded quoted-printable)
On Fri, 2 Dec 2005, Buehler, Martin wrote:
{Quote hidden}> > Why does a one's complement of an 'unsigned char' not return an 'unsigned char'?
> > example:
> > unsigned char a,b;
> > a = 0x03;
> b = ~a; //b = 0xfc
> > if (a == ~b) {/* true */}
> else {/* false */}
> > according to my understanding, this should always evaluate to 'true', as ´~b' is 0x03.
> but it does not! it always evaluates to 'false'.
> a bitwise one's complement seems to return an undefined width, instead of a 8 bit value (unsigned char).
> > i found several workarounds to evaluate to true:
> > 1) signed char a,b; (instead of unsigned) -> i really don't like signed char for logic operations
> > 2) if (a == (unsigned char)~b) {/* true */} -> seems to be the most efficient way
> > 3) if (a == (~b & 0xff)) {/* true */} -> requires more memory
> > although i found a workaround for the problem, i do not really understand why it does not automatically reduce the with to unsigned char, if only unsigned chars are involved.
> > i searche through my c reference book, but found nothing on this.
> > anyone knows?
"b" is being promoted to "int" before the "~" is applied.
Regards
Sergio Masci
http://www.xcprod.com/titan/XCSB - optimising PIC compiler
FREE for personal non-commercial use
.
part 2 35 bytes content-type:text/plain; charset="us-ascii"
(decoded 7bit)
2005\12\02@062345
by
Buehler, Martin
******************************************************************************************************
>{Original Message removed}
2005\12\02@063842
by
PY2NI TERRA
Well, using CC5X your fragment of code works as it should, no workaround
required,
probably your compiler is pulling your leg somehow.
Horta
{Original Message removed}
2005\12\02@070711
by
Gerhard Fiedler
|
Preamble: Everything I say depends a bit on the specific compiler and how
it implements implicit integer type promotions. I'm talking about ANSI C89,
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 'unsigned
> char'?
Short answer: because all operations on types smaller than int are done as
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;
>
> a = 0x03; b = ~a; //b = 0xfc
"b = ~a;" can also be written as
{
int _internal_temp = a;
_internal_temp = ~_internal_temp;
b = (unsigned char)_internal_temp;
}
> if (a == ~b) {/* true */} else {/* false */}
>
> according to my understanding, this should always evaluate to 'true', as
> ´~b' is 0x03. but it does not! it always evaluates to 'false'. a bitwise
> one's complement seems to return an undefined width, instead of a 8 bit
> value (unsigned char).
The expression (a == ~b) gets evaluated like this:
{
int _internal_temp_b = b; // high byte is 0, because b is unsigned
_internal_temp_b = ~_internal_temp_b; // high byte is now 0xff
int _internal_temp_a = a; // high byte is 0, because a is unsigned
return (_internal_temp_a == _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:
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
Declaring a and b as signed changes the handling of the high bytes, because
the sign bit gets now extended into the high byte. The expression (a == ~b)
gets now evaluated like this:
{
int _internal_temp_b = b; // high byte is 0xff, because b is signed and
negative
_internal_temp_b = ~_internal_temp_b; // high byte is now 0
int _internal_temp_a = a; // high byte is 0, because a is signed and
positive
return (_internal_temp_a == _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 == (unsigned char)~b) {/* true */} -> seems to be the most
> efficient way
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 type
(unsigned char) before the next operation (==). The result of this cast is
that you are comparing two unsigned chars, which get again promoted to int
for ==, but in the same way (with the high byte being 0 for both).
> 3) if (a == (~b & 0xff)) {/* true */} -> requires more memory
That is similar to 2), but less clean, in that it only clears the high byte
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 what
they seem to say they are, independently of the particular compiler. :)
For more information, look for implicit conversions in a C standard and in
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
2005\12\02@074243
by
Michael Rigby-Jones
|
>-----Original Message-----
>From: spam_OUTpiclist-bouncesTakeThisOuT
mit.edu [.....piclist-bouncesKILLspam
@spam@mit.edu]
>Sent: 02 December 2005 12:04
>To: piclist
KILLspammit.edu
>Subject: Re: [PIC] C-Compiler: One's complement of unsigned char
>
>
>(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 what they seem to
>say they are, independently of the particular compiler. :)
It would be good practice to start using the C99 fixed integer size types rather than roll your own:
uint8_t
uint16_t
uint32_t
int8_t
int16_t
int32_t
Regards
Mike
=======================================================================
This e-mail is intended for the person it is addressed to only. The
information contained in it may be confidential and/or protected by
law. If you are not the intended recipient of this message, you must
not make any use of this information, or copy or show it to any
person. Please contact us immediately to tell us that you have
received this e-mail, and return the original to us. Any use,
forwarding, printing or copying of this message is strictly prohibited.
No part of this message can be considered a request for goods or
services.
=======================================================================
2005\12\02@074519
by
William Chops Westfield
On Dec 2, 2005, at 3:39 AM, PY2NI_TERRA wrote:
> using CC5X your fragment of code works as it should, no workaround
> required, probably your compiler is pulling your leg somehow.
>
x86 gcc behaves as described in the original post ("False" case.)
See Gerhard's excellent explanation; presumably cc5x uses 8bits for
"int", which is probably technically a standard violation but (IMO)
permissible or even useful for an embedded 8bit processor...
BillW
2005\12\02@084355
by
Gerhard Fiedler
Michael Rigby-Jones wrote:
> It would be good practice to start using the C99 fixed integer size types
> rather than roll your own:
>
> uint8_t uint16_t uint32_t int8_t int16_t int32_t
Thanks for the tip; I might start doing that, or on second thought maybe
not...
I started with that before C99, and so far there are not many C99 compliant
compilers out there to really make a difference. If I should get to work
with one, it may just get simple typedefs in a common include file (I
always need one anyway). It's just a lot simpler to type u8 than it is to
type uint8_t... and I don't need the _t suffix; my editor knows how a
symbol is defined :)
Gerhard
2005\12\02@085229
by
Buehler, Martin
thanx a lot!
i think i'll got it...
tino
******************************************************************************************************
>{Original Message removed}
2005\12\02@123916
by
John Temples
On Fri, 2 Dec 2005, Buehler, Martin wrote:
> Why does a one's complement of an 'unsigned char' not return an 'unsigned char'?
> i searche through my c reference book, but found nothing on this.
Look up "integer promotion" in your book.
--
John W. Temples, III
More... (looser matching)
- Last day of these posts
- In 2005
, 2006 only
- Today
- New search...