Velocity Reviews > 'Unsigned decimal'

# 'Unsigned decimal'

BartC
Guest
Posts: n/a

 11-02-2012
I have this code:

int a = -2147483648;
long long int b = 2147483648;

And gcc gives me this warning for each:

"warning: this decimal constant is unsigned only in ISO C90"

These types are signed 32 and 64 bits respectively. How to get rid of this
warning? What is it's problem anyway, in the second example?

(For the first, I guess that 2147483648 is out of range before the negation
is applied.)

--
Bartc

Les Cargill
Guest
Posts: n/a

 11-02-2012
BartC wrote:
> I have this code:
>
> int a = -2147483648;
> long long int b = 2147483648;
>
> And gcc gives me this warning for each:
>
> "warning: this decimal constant is unsigned only in ISO C90"
>
> These types are signed 32 and 64 bits respectively. How to get rid of
> this warning? What is it's problem anyway, in the second example?
>
> (For the first, I guess that 2147483648 is out of range before the
> negation is applied.)
>

Nope. -2147483648 is a perfectly valid ( although somewhat
ambiguous ) 32 bit value ( assuming long is 32 bits for
what you are doing ). It is 0x8000000. So is 2147483648.

0x80000000 is never ambiguous.

I would use hex:

C:\c\usenet>cat long.c

//signed long int a = (signed int)-2147483648L;
//signed long long int b = (signed int)2147483648LL;

signed long int a = 0x80000000L;
signed long long int b = 0x80000000LL;
int main(void)
{

printf("a=%ld\n",a);
printf("b=%lld\n",b);

printf("a=%08lx\n",a);
printf("b=%08llx\n",b);
return 0;
}

Output:

C:\c\usenet>a
a=-2147483648
b=2147483648
a=80000000
b=80000000

--
Les Cargill

Ben Pfaff
Guest
Posts: n/a

 11-02-2012
"BartC" <(E-Mail Removed)> writes:

> I have this code:
>
> int a = -2147483648;
> long long int b = 2147483648;
>
> And gcc gives me this warning for each:
>
> "warning: this decimal constant is unsigned only in ISO C90"
>
> These types are signed 32 and 64 bits respectively. How to get rid of
> this warning? What is it's problem anyway, in the second example?

One approach is to write:

int a = -2147483647 - 1;
long long int b = 2147483648LL;

James Kuyper
Guest
Posts: n/a

 11-02-2012
On 11/02/2012 01:34 PM, BartC wrote:
> I have this code:
>
> int a = -2147483648;
> long long int b = 2147483648;
>
> And gcc gives me this warning for each:
>
> "warning: this decimal constant is unsigned only in ISO C90"
>
> These types are signed 32 and 64 bits respectively. How to get rid of this
> warning? What is it's problem anyway, in the second example?

I suspect you're using a system where INT_MAX==LONG_MAX==214783647;
that's the case on my system, and I can reproduce your warning message
when compiling for C90. According to the C99 rules, if 214783648 >
LONG_MAX, then 214783648 has the type long long int. In C90, that was
not an option, so I would guess that 214783648 had the type 'unsigned int'.
Because unary minus is a operator, and not part of the integer literal
syntax, you can't actually express INT_MIN as integer literal of type
'int', when 'int' is a 2's complement type. The closest you can come is
(-21478367-1).

In the second case, it's simpler. Just apply the LL suffix to force
interpretation as a long long integer literal.

James Kuyper
Guest
Posts: n/a

 11-02-2012
On 11/02/2012 01:49 PM, Les Cargill wrote:
> BartC wrote:
>> I have this code:
>>
>> int a = -2147483648;
>> long long int b = 2147483648;
>>
>> And gcc gives me this warning for each:
>>
>> "warning: this decimal constant is unsigned only in ISO C90"
>>
>> These types are signed 32 and 64 bits respectively. How to get rid of
>> this warning? What is it's problem anyway, in the second example?
>>
>> (For the first, I guess that 2147483648 is out of range before the
>> negation is applied.)
>>

>
> Nope. -2147483648 is a perfectly valid ( although somewhat
> ambiguous ) 32 bit value ( assuming long is 32 bits for
> what you are doing ). It is 0x8000000. So is 2147483648.

In C90, you'd be correct - which just means that it's out of range for
'int' both before, and after, the unary minus is evaluated.

In C99 or later, it has type long long, which he's told us is a 64-bit
type on his system.

Keith Thompson
Guest
Posts: n/a

 11-02-2012
Les Cargill <(E-Mail Removed)> writes:
> BartC wrote:
>> I have this code:
>>
>> int a = -2147483648;
>> long long int b = 2147483648;
>>
>> And gcc gives me this warning for each:
>>
>> "warning: this decimal constant is unsigned only in ISO C90"
>>
>> These types are signed 32 and 64 bits respectively. How to get rid of
>> this warning? What is it's problem anyway, in the second example?
>>
>> (For the first, I guess that 2147483648 is out of range before the
>> negation is applied.)
>>

>
> Nope. -2147483648 is a perfectly valid ( although somewhat
> ambiguous ) 32 bit value ( assuming long is 32 bits for
> what you are doing ). It is 0x8000000. So is 2147483648.
>
> 0x80000000 is never ambiguous.

Not quite.

In C99 and later, a decimal constant's type is the first of:

int, long int, long long int

in which it fits. In C90 (before long long was invented), the
sequence takes a left turn into unsigned land:

int, long int, unsigned long int

-2147483648 is not a constant; it's a constant expression consisting
of a unary "-" applied to the contant 2147483648.

Assuming int and long are 32 bits and long long is 64 bits (if it
exists), in C90 the constant 2147483648 is of type unsigned long.
Applying unary "-" to it yields an unsigned long result with
the same value. Initializing the int object "a" with that value
causes it to be converted from unsigned long to (signed) int --
which, since 2147483648L is outside the range of int, yields an
implementation-defined value. That value is very likely to be
-2147483648, which is what was intended.

In C99 and later the constant 2147483648 is of type long long, since
it won't fit in a long. Applying unary "-" gives you an expression
of type long long with the value -2147483648. Converting that
value to int unambiguously yields the int value -2147483648.

So as of C99, the declaration

int a = -2147483648;

is unambiguous and initializes a to the obvious value; in C90, it
*probably* does so.

The rules for octal and hexadecimal constants are a bit different. In
C90, the sequence is:

int, unsigned int, long int, unsigned long int

and in C99 and later, its:

int, unsigned int, long int, unsigned long int, long long int,
unsigned long long int

So changing the declaration to:

int a = -0x80000000

doesn't help for C90 (though it may remove the warning); the constant
is of type unsigned int, and the conversion is implementation-defined
(but very likely to yield the result you want). And in C99 and
later, it actually introduces an ambiguity, since -0x80000000 is of
type unsigned int, whereas -2147483648 is of type (signed) long long.

The warning, I think, refers just to the constant 2147483648,
without regard to its context.

If you're willing to assume that int is 32 bits (more specifically,
that INT_MIN == -2147483648 (mathematically)), then you can just
write:

int a = INT_MIN;

If not, you can write:

int a = -2147483647-1;

to avoid the warning.

For the second declaration, you could write:

long long int b = 2147483647+1;

or

long long int b = 2147483648LL;

If you can't assume that int is at least 32 bits, things could
get a bit more complicated; there's no guarantee that the value
-2147483648 can be stored in an int.

--
Keith Thompson (The_Other_Keith) http://www.velocityreviews.com/forums/(E-Mail Removed) <http://www.ghoti.net/~kst>
Will write code for food.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Joe Pfeiffer
Guest
Posts: n/a

 11-02-2012
"BartC" <(E-Mail Removed)> writes:

> I have this code:
>
> int a = -2147483648;
> long long int b = 2147483648;
>
> And gcc gives me this warning for each:
>
> "warning: this decimal constant is unsigned only in ISO C90"
>
> These types are signed 32 and 64 bits respectively. How to get rid of
> this warning? What is it's problem anyway, in the second example?
>
> (For the first, I guess that 2147483648 is out of range before the
> negation is applied.)

The variables you're declaring are int and long long int, but the
constants are ints (note that the first one is a unary operator being
applied to a constant -- it isn't a negative constant. In the standard,
a decimal constant is just the digits, not the leading minus sign). The
compiler is warning you that ints can't represent those constants; they
have to be unsigned.

If you replace them with

int a = -2147483648u;
long long int b = 2147483648u;

(telling the compiler to make them unsigned)

or

int a = -2147483648ll;
long long int b = 2147483648ll;

(telling it you want them to be 64 bit)

the warnings go away, and the initialization successfully converts them
to what you had in mind.

Keith Thompson
Guest
Posts: n/a

 11-02-2012
Joe Pfeiffer <(E-Mail Removed)> writes:
> "BartC" <(E-Mail Removed)> writes:
>> I have this code:
>> int a = -2147483648;
>> long long int b = 2147483648;
>>
>> And gcc gives me this warning for each:
>>
>> "warning: this decimal constant is unsigned only in ISO C90"
>>
>> These types are signed 32 and 64 bits respectively. How to get rid of
>> this warning? What is it's problem anyway, in the second example?
>>
>> (For the first, I guess that 2147483648 is out of range before the
>> negation is applied.)

>
> The variables you're declaring are int and long long int, but the
> constants are ints (note that the first one is a unary operator being
> applied to a constant -- it isn't a negative constant. In the standard,
> a decimal constant is just the digits, not the leading minus sign). The
> compiler is warning you that ints can't represent those constants; they
> have to be unsigned.

Given INT_MAX==2147483647 and LONG_MAX==2147483647, 2147483648
cannot be of type int. It's of type unsigned long in C90, signed
long long in C99 and up. See my other followup for details.

> If you replace them with
>
> int a = -2147483648u;
> long long int b = 2147483648u;
>
> (telling the compiler to make them unsigned)
>
> or
>
> int a = -2147483648ll;
> long long int b = 2147483648ll;
>
> (telling it you want them to be 64 bit)
>
> the warnings go away, and the initialization successfully converts them
> to what you had in mind.

Adding a "u" suffix may inhibit the warning, but it won't
fix the problem that the unsigned-to-signed conversion has an
implementation-defined result. The "LL" suffix (don't use "ll", it
looks too much like "11") guarantees that the constant is signed, and
makes the conversion well defined (assuming int is at least 32 bits).
It kills portability to pre-C99 compilers; that may not be an issue.

--
Keith Thompson (The_Other_Keith) (E-Mail Removed) <http://www.ghoti.net/~kst>
Will write code for food.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

BartC
Guest
Posts: n/a

 11-02-2012

"BartC" <(E-Mail Removed)> wrote in message news:k7108j\$1t4\$(E-Mail Removed)...

> int a = -2147483648;
> long long int b = 2147483648;
>
> And gcc gives me this warning for each:
>
> "warning: this decimal constant is unsigned only in ISO C90"

Thanks for the replies. I've replaced instances of -2147483648 with
0x80000000 where an int is expected. And using an LL suffix for any long
long ints.

That's shut the compiler up for now. (These numbers occur in data
initialisation lists written by external software; the ints have to be
specially detected so as to generate the alternate form. Doubtless the same
problem will crop up elsewhere and will need fixing too. Odd that I can't
just write a legal int value, 0x80000000, in decimal!)

(I would have used the -cstd=C99 option in gcc if it had helped, but I tried
to use that yesterday to provide designated initialisers for one of my
complex structs, but it didn't like the 3-deep unnamed unions and structs
that it uses. Since I need that struct as it is, I think that C99 is out!)

--
Bartc

Keith Thompson
Guest
Posts: n/a

 11-02-2012
"BartC" <(E-Mail Removed)> writes:
> "BartC" <(E-Mail Removed)> wrote in message news:k7108j\$1t4\$(E-Mail Removed)...
>> int a = -2147483648;
>> long long int b = 2147483648;
>>
>> And gcc gives me this warning for each:
>>
>> "warning: this decimal constant is unsigned only in ISO C90"

>
> Thanks for the replies. I've replaced instances of -2147483648 with
> 0x80000000 where an int is expected. And using an LL suffix for any long
> long ints.

That eliminates the warning (because 0x8000000 is of type
unsigned int in both C90 and C99), but you're still doing an
implementation-defined conversion from unsigned to signed.
It's *probably* safe to assume that 0x80000000 converts to
(int)-2147483648; you'll have to decide whether that's good enough.

Using 2147483648LL should eliminate both the warning and the
implementation-definedness of the conversion -- if you can assume
support for the LL suffix.

> That's shut the compiler up for now. (These numbers occur in data
> initialisation lists written by external software; the ints have to be
> specially detected so as to generate the alternate form. Doubtless the same
> problem will crop up elsewhere and will need fixing too. Odd that I can't
> just write a legal int value, 0x80000000, in decimal!)

Because 0x8000000 isn't a legal int value; INT_MAX on your system is
0x7FFFFFFF.

> (I would have used the -cstd=C99 option in gcc if it had helped, but I tried
> to use that yesterday to provide designated initialisers for one of my
> complex structs, but it didn't like the 3-deep unnamed unions and structs
> that it uses. Since I need that struct as it is, I think that C99 is out!)

C11 supports unnamed unions and structs. Depending on how
recent your gcc is, you can probably use "-std=c11 -pedantic" or
"-std=c1x -pedantic". (With "-std=c99" but without "-pedantic", gcc
doesn't complain about unnamed unions and structs.)

--
Keith Thompson (The_Other_Keith) (E-Mail Removed) <http://www.ghoti.net/~kst>
Will write code for food.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"