Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C Programming (http://www.velocityreviews.com/forums/f42-c-programming.html)
-   -   hex and unsigned and signed decimal (http://www.velocityreviews.com/forums/t445685-hex-and-unsigned-and-signed-decimal.html)

me2 12-28-2006 02:32 PM

hex and unsigned and signed decimal
 
I am writing a little base conversion utility called base.c.

This is what base does.

$ base -127
Signed decimal: -127
Unsigned decimal: 4294967169
Hexidecimal: 0xffffff81
Octal: O37777777601
Binary: 1098 7654 3210 9876 5432 1098 7654 3210
1111 1111 1111 1111 1111 1111 1000 0001
$ base 127
Signed decimal: 127
Unsigned decimal: 127
Hexidecimal: 0x7f
Octal: O177
Binary: 1098 7654 3210 9876 5432 1098 7654 3210
0000 0000 0000 0000 0000 0000 0111 1111

However, base has a bug when one inputs sign extended hexadecimal or octal
numbers, like this.

$ base 0xffffff81
Signed decimal: 2147483647
Unsigned decimal: 2147483647
Hexidecimal: 0x7fffffff
Octal: O17777777777
Binary: 1098 7654 3210 9876 5432 1098 7654 3210
0111 1111 1111 1111 1111 1111 1111 1111

Base works like this. I use sscanf %i to convert argv[1] to an int. Then
I cast the int to an unsigned int and do the rest of the manipulation.
However, as the above example shows, it doesn't work properly when I input
a sign extended octal or hex number.

The decimal of 0xffffff81 should be 4294967169, but it isn't. Why ?

Thanks

Scorpio 12-28-2006 03:04 PM

Re: hex and unsigned and signed decimal
 

me2 wrote:
> I am writing a little base conversion utility called base.c.
>
> This is what base does.
>
> $ base -127
> Signed decimal: -127
> Unsigned decimal: 4294967169
> Hexidecimal: 0xffffff81
> Octal: O37777777601
> Binary: 1098 7654 3210 9876 5432 1098 7654 3210
> 1111 1111 1111 1111 1111 1111 1000 0001
> $ base 127
> Signed decimal: 127
> Unsigned decimal: 127
> Hexidecimal: 0x7f
> Octal: O177
> Binary: 1098 7654 3210 9876 5432 1098 7654 3210
> 0000 0000 0000 0000 0000 0000 0111 1111
>
> However, base has a bug when one inputs sign extended hexadecimal or octal
> numbers, like this.
>
> $ base 0xffffff81
> Signed decimal: 2147483647
> Unsigned decimal: 2147483647
> Hexidecimal: 0x7fffffff
> Octal: O17777777777
> Binary: 1098 7654 3210 9876 5432 1098 7654 3210
> 0111 1111 1111 1111 1111 1111 1111 1111
>
> Base works like this. I use sscanf %i to convert argv[1] to an int. Then
> I cast the int to an unsigned int and do the rest of the manipulation.
> However, as the above example shows, it doesn't work properly when I input
> a sign extended octal or hex number.
>
> The decimal of 0xffffff81 should be 4294967169, but it isn't. Why ?


Because %i is only for integers. You will need to check the string in
argv[1] before scanning it using sscanf. If it is preceded with "0x"
then use %x (hexadecimal), if its preceded with just "0" then use %o
(octal) for scanning with sprintf, and later you can convert it to
other formats.


Scorpio 12-28-2006 03:08 PM

Re: hex and unsigned and signed decimal
 

Scorpio wrote:
> me2 wrote:
> > I am writing a little base conversion utility called base.c.
> >
> > This is what base does.
> >
> > $ base -127
> > Signed decimal: -127
> > Unsigned decimal: 4294967169
> > Hexidecimal: 0xffffff81
> > Octal: O37777777601
> > Binary: 1098 7654 3210 9876 5432 1098 7654 3210
> > 1111 1111 1111 1111 1111 1111 1000 0001
> > $ base 127
> > Signed decimal: 127
> > Unsigned decimal: 127
> > Hexidecimal: 0x7f
> > Octal: O177
> > Binary: 1098 7654 3210 9876 5432 1098 7654 3210
> > 0000 0000 0000 0000 0000 0000 0111 1111
> >
> > However, base has a bug when one inputs sign extended hexadecimal or octal
> > numbers, like this.
> >
> > $ base 0xffffff81
> > Signed decimal: 2147483647
> > Unsigned decimal: 2147483647
> > Hexidecimal: 0x7fffffff
> > Octal: O17777777777
> > Binary: 1098 7654 3210 9876 5432 1098 7654 3210
> > 0111 1111 1111 1111 1111 1111 1111 1111
> >
> > Base works like this. I use sscanf %i to convert argv[1] to an int. Then
> > I cast the int to an unsigned int and do the rest of the manipulation.
> > However, as the above example shows, it doesn't work properly when I input
> > a sign extended octal or hex number.
> >
> > The decimal of 0xffffff81 should be 4294967169, but it isn't. Why ?

>
> Because %i is only for integers. You will need to check the string in
> argv[1] before scanning it using sscanf. If it is preceded with "0x"
> then use %x (hexadecimal), if its preceded with just "0" then use %o
> (octal) for scanning with sprintf, and later you can convert it to
> other formats.


Correction...I meant scanning with sscanf, not sprintf. Sorry.


Scorpio 12-28-2006 04:11 PM

Re: hex and unsigned and signed decimal
 

Scorpio wrote:
> Scorpio wrote:
> > me2 wrote:
> > > I am writing a little base conversion utility called base.c.
> > >
> > > This is what base does.
> > >
> > > $ base -127
> > > Signed decimal: -127
> > > Unsigned decimal: 4294967169
> > > Hexidecimal: 0xffffff81
> > > Octal: O37777777601
> > > Binary: 1098 7654 3210 9876 5432 1098 7654 3210
> > > 1111 1111 1111 1111 1111 1111 1000 0001
> > > $ base 127
> > > Signed decimal: 127
> > > Unsigned decimal: 127
> > > Hexidecimal: 0x7f
> > > Octal: O177
> > > Binary: 1098 7654 3210 9876 5432 1098 7654 3210
> > > 0000 0000 0000 0000 0000 0000 0111 1111
> > >
> > > However, base has a bug when one inputs sign extended hexadecimal or octal
> > > numbers, like this.
> > >
> > > $ base 0xffffff81
> > > Signed decimal: 2147483647
> > > Unsigned decimal: 2147483647
> > > Hexidecimal: 0x7fffffff
> > > Octal: O17777777777
> > > Binary: 1098 7654 3210 9876 5432 1098 7654 3210
> > > 0111 1111 1111 1111 1111 1111 1111 1111
> > >
> > > Base works like this. I use sscanf %i to convert argv[1] to an int. Then
> > > I cast the int to an unsigned int and do the rest of the manipulation.
> > > However, as the above example shows, it doesn't work properly when I input
> > > a sign extended octal or hex number.
> > >
> > > The decimal of 0xffffff81 should be 4294967169, but it isn't. Why ?

> >
> > Because %i is only for integers. You will need to check the string in
> > argv[1] before scanning it using sscanf. If it is preceded with "0x"
> > then use %x (hexadecimal), if its preceded with just "0" then use %o
> > (octal) for scanning with sprintf, and later you can convert it to
> > other formats.

>
> Correction...I meant scanning with sscanf, not sprintf. Sorry.


More correction. I just realized that %x and %o are only for printing,
and its cannot be used for scanning. So you'll have to find some other
method to read hexadecimal and octal values.


CBFalconer 12-28-2006 04:14 PM

Re: hex and unsigned and signed decimal
 
me2 wrote:
>

.... snip ...
>
> However, base has a bug when one inputs sign extended hexadecimal
> or octal numbers, like this.
>
> $ base 0xffffff81
> Signed decimal: 2147483647
> Unsigned decimal: 2147483647
> Hexidecimal: 0x7fffffff
> Octal: O17777777777
> Binary: 1098 7654 3210 9876 5432 1098 7654 3210
> 0111 1111 1111 1111 1111 1111 1111 1111
>
> Base works like this. I use sscanf %i to convert argv[1] to an
> int. Then I cast the int to an unsigned int and do the rest of
> the manipulation. However, as the above example shows, it doesn't
> work properly when I input a sign extended octal or hex number.
>
> The decimal of 0xffffff81 should be 4294967169, but it isn't.
> Why ?


You have experienced integer overflow, after which behaviour is
undefined. Therefore the answers you are getting (or anything
else) are perfectly valid.

--
Merry Christmas, Happy Hanukah, Happy New Year
Joyeux Noel, Bonne Annee.
Chuck F (cbfalconer at maineline dot net)
<http://cbfalconer.home.att.net>



me2 12-28-2006 04:27 PM

Re: hex and unsigned and signed decimal
 
On Thu, 28 Dec 2006 07:04:32 -0800, Scorpio wrote:

> Because %i is only for integers. You will need to check the string in
> argv[1] before scanning it using sscanf. If it is preceded with "0x"
> then use %x (hexadecimal), if its preceded with just "0" then use %o
> (octal) for scanning with sprintf, and later you can convert it to
> other formats.


But man sscanf says this:

The following conversion specifiers are available:
....

i Matches an optionally signed integer; the next pointer must be a
pointer to int. The integer is read in base 16 if it
begins with 0x or 0X, in base 8 if it begins with 0, and
in base 10 otherwise. Only characters that correspond to
the base are used.

So why isn't it properly reading the hex and octal numbers ?

Thanks.

Michal Nazarewicz 12-29-2006 10:16 AM

Re: hex and unsigned and signed decimal
 
me2 <nobody@nowhere.com> writes:

> I am writing a little base conversion utility called base.c.
>
> This is what base does.

[cut]
> However, base has a bug when one inputs sign extended hexadecimal or octal
> numbers, like this.

[cut]
> I use sscanf %i to convert argv[1] to an int.


You'd better use strtol() for that which can automatically read
decimal, octal or hexadecimal numbers and provides better error
checking I guess. You could even use strtoll() for bigger numbers if
it's available on your system (I believe it's defined in C99).

#v+
#include <stdio.h>
#include <stdlib.o>
#include <errno.h>

int main(int argc, char **argv) {
char *end;
long long num;

if (argc!=2) {
fputs("usage: base <number>\n", stderr);
return EXIT_FAILURE;
}

num = strtoll(argv[1], &end, 0);
if (*end || errno) {
fprintf(stder, "%s: invalid number\n", argv[1]);
return EXIT_FAILURE;
}

printf("signed : %lld\n", num);
printf("unsigned: %llu\n", num);
printf("hex : %llo\n", num);
printf("octal : %llx\n", num);
return EXIT_SUCESS;
}
#v-

(code not tested)


--
Best regards, _ _
.o. | Liege of Serenly Enlightened Majesty of o' \,=./ `o
..o | Computer Science, Michal "mina86" Nazarewicz (o o)
ooo +--<mina86*tlen.pl>---<jid:mina86*chrome.pl>--ooO--(_)--Ooo--

Hallvard B Furuseth 12-29-2006 10:32 AM

Re: hex and unsigned and signed decimal
 
Michal Nazarewicz writes:
> You'd better use strtol() for that which can automatically read
> decimal, octal or hexadecimal numbers and provides better error
> checking I guess. You could even use strtoll() for bigger numbers if
> it's available on your system (I believe it's defined in C99).


Or lacking long long, handle the sign specially and read the rest into
an unsigned int with strtoul or %u. Then maybe convert to int - taking
care to avoid overflow, including for INT_MIN.

--
Hallvard

me2 12-29-2006 04:50 PM

Re: hex and unsigned and signed decimal
 
On Thu, 28 Dec 2006 11:14:06 -0500, CBFalconer wrote:


> You have experienced integer overflow, after which behaviour is
> undefined. Therefore the answers you are getting (or anything
> else) are perfectly valid.


0xffffff81 is a 32 bit number. How can it be integer overflow ? Are you
saying it will interpret it as an unsigned integer and then try to stuff
it in a signed int variable and overflow that way ?

me2 12-29-2006 04:57 PM

Re: hex and unsigned and signed decimal
 
On Fri, 29 Dec 2006 11:16:00 +0100, Michal Nazarewicz wrote:

Changing it to use strtol and a long prevented the overflow. It works
properly now.


All times are GMT. The time now is 11:32 AM.

Powered by vBulletin®. Copyright ©2000 - 2013, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57