Velocity Reviews > hex and unsigned and signed decimal

# hex and unsigned and signed decimal

me2
Guest
Posts: n/a

 12-28-2006
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
Guest
Posts: n/a

 12-28-2006

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
Guest
Posts: n/a

 12-28-2006

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
Guest
Posts: n/a

 12-28-2006

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

CBFalconer
Guest
Posts: n/a

 12-28-2006
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
Guest
Posts: n/a

 12-28-2006
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
Guest
Posts: n/a

 12-29-2006
me2 <(E-Mail Removed)> 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
Guest
Posts: n/a

 12-29-2006
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
Guest
Posts: n/a

 12-29-2006
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
Guest
Posts: n/a

 12-29-2006
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.