decimal constant too large

K

kerravon

The following C program:

int main(void)
{
int x = -2147483648;

return (0);
}

Produces the following warning:

temp.c: In function `main':
temp.c:3: warning: decimal constant is so large that it is unsigned

on gcc on Win98 and MVS.

As far as I can tell, that is in fact the maximum negative number on
those
environments and therefore the constant fits into a signed integer and
therefore I shouldn't be getting a warning.

Any ideas? I checked the FAQ but didn't see anything.

Thanks. Paul.
 
C

Chris Dollin

kerravon said:
The following C program:

int main(void)
{
int x = -2147483648;

return (0);
}

Produces the following warning:

temp.c: In function `main':
temp.c:3: warning: decimal constant is so large that it is unsigned

on gcc on Win98 and MVS.

As far as I can tell, that is in fact the maximum negative number on
those
environments and therefore the constant fits into a signed integer and
therefore I shouldn't be getting a warning.

`-2147483648` isn't a decimal constant; it's an expression. The decimal
constant in question is `2147483648`, which is one bigger than can be
expressed in a 32-bit signed integer.
 
K

kerravon

`-2147483648` isn't a decimal constant; it's an expression. The decimal
constant in question is `2147483648`, which is one bigger than can be
expressed in a 32-bit signed integer.

I see. So is the solution then to make it -2147483648U ?

I can see from other people's limits.h that they have made it
(-2147483647-1). Why would they do that instead of sticking a U
on the end? Is it because the U on the end will force everything
into unsigned arithmetic?

Thanks. Paul.
 
M

Martien Verbruggen

The following C program:

int main(void)
{
int x = -2147483648;

return (0);
}

Produces the following warning:

temp.c: In function `main':
temp.c:3: warning: decimal constant is so large that it is unsigned

Assuming that you're right and that INT_MIN on your system is indeed
-2147483648 (and INT_MAX 2147483647):

I suspect that gcc sees the constant as two tokens: '-' and 2147483648.
2147483648 is larger than INT_MAX, which is what probably
triggers the warning. Try to see if the warning goes away if you write:

int x = -INT_MAX - 1;

Martien
 
B

Ben Bacarisse

kerravon said:
The following C program:

int main(void)
{
int x = -2147483648;

return (0);
}

Produces the following warning:

temp.c: In function `main':
temp.c:3: warning: decimal constant is so large that it is unsigned

on gcc on Win98 and MVS.

As far as I can tell, that is in fact the maximum negative number on
those environments and therefore the constant fits into a signed
integer and therefore I shouldn't be getting a warning.

Except C has no negative literals. Your initializer is an expression:
the unary negation operator is applied to a constant. That constant,
2147483648, is indeed so large that it is unsigned (in C90). Negating
this large unsigned number provokes, technically, integer overflow.

The best way to at you system limits is with:

#include <limits.h>

There you will find INT_MIN. On my system, its definition is
(-INT_MAX - 1). Can see how this avoids any overflow?

There was a subtle change in C99 -- the number 2147483648 must be
interpreted as having type 'signed long long int'. Both because long
long was introduced but also because the rules about what constants
are taken to be signed and unsigned were changed. Thus in C99 there
is no overflow since the negated long long int does, just, fit into an
int.

Obviously the numbers will be different on systems with other integer
sizes.
 
J

James Kuyper

kerravon said:
I see. So is the solution then to make it -2147483648U ?

No, -2147483648U is an expression containing the unary '-' operator
acting on an unsigned integer; the result will therefore also have an
unsigned integer type, and therefore a positive value.
I can see from other people's limits.h that they have made it
(-2147483647-1). Why would they do that instead of sticking a U
on the end? Is it because the U on the end will force everything
into unsigned arithmetic?

Yes, that is the reason. When the mathematical value of INT_MIN is
-2147483648, the C expression (-2147483647-1) is one of the simplest
expressions that has that value.
 
S

Serve Lau

Ben Bacarisse said:
There was a subtle change in C99 -- the number 2147483648 must be
interpreted as having type 'signed long long int'. Both because long
long was introduced but also because the rules about what constants
are taken to be signed and unsigned were changed.

Can you generalize this a bit more?

Every integer constant is taken as a long long in C99?
 
C

CBFalconer

kerravon said:
The following C program:

int main(void) {
int x = -2147483648;
return (0);
}

Produces the following warning:

temp.c: In function `main':
temp.c:3: warning: decimal constant is so large that it is unsigned

on gcc on Win98 and MVS.

As far as I can tell, that is in fact the maximum negative number
on those environments and therefore the constant fits into a signed
integer and therefore I shouldn't be getting a warning.

The expression consists of the positive integer 2147483648 and a
negation. The positive integer doesn't fit. You can form the
value with "-2147483648 - 1" on 32 bit systems. On 16 bit (or 31
bit, etc.) systems you will need to use a long.

Another option is:

int x = INT_MIN;

after #include <limits.h>
 
B

Ben Bacarisse

Serve Lau said:
Can you generalize this a bit more?

Every integer constant is taken as a long long in C99?

No. A decimal constant that has no suffix (u, l, etc) will be taken
to be the first of int, long int, long long int that can represent the
value. The full description of how suffixes and prefixes (denoting
octal and hex constants) affect the resulting type is best described
as in it in the standard -- as a table. Octal and hex constants can
either unsigned or signed and the suffixes impose the obvious
restrictions but the table is the clearest way of seeing it all.

In C90 an unadorned decimal constant has type int, long int or
unsigned long int, whichever is the first to be able to represent the
value. Apart from the fact C90 has no long long types, this is
pretty much the only difference.
 
J

James Kuyper

Serve said:
Can you generalize this a bit more?

Every integer constant is taken as a long long in C99?

No - what he said is based upon the implied assumption that LONG_MAX is
2147483647. If LONG_MAX > 2147483647, then the type of 2147483648 could
be long int. If INT_MAX > 2147483647, the type of 2147483648 would be
plain int.

The rules for determining the type of an integer constant are given in
section 6.4.4.1p5 and p6. They depend upon many things. It's unsigned if
a 'U' or a 'u' suffix is applied, and it's at least as big as a long if
an 'L' or 'l' suffix is applied, and it's at least as big as a long long
if an 'LL' or 'll' suffix is used. Decimal constants have an unsigned
type only if explicitly labeled with the 'U' or 'u' suffix, or if they
are too big for long long. In contrast, octal and hexadecimal constants
without that suffix can have either a signed or unsigned type. Within
those constraints, the type of an integer constant is generally the
smallest standard type that is big enough to represent that value,
except that is never a type smaller than 'int'. If none of the standard
types is big enough to hold the specified value, an extended integer
type can be used instead.
 
J

Joe Wright

CBFalconer said:
The expression consists of the positive integer 2147483648 and a
negation. The positive integer doesn't fit. You can form the
value with "-2147483648 - 1" on 32 bit systems. On 16 bit (or 31
bit, etc.) systems you will need to use a long.

Another option is:

int x = INT_MIN;

after #include <limits.h>
Off-by-one? From my limits.h

#define INT_MAX 2147483647
#define INT_MIN (-2147483647-1)
 
K

Keith Thompson

Joe Wright said:
CBFalconer said:
kerravon said:
The following C program:

int main(void) {
int x = -2147483648;
return (0);
}

Produces the following warning:

temp.c: In function `main':
temp.c:3: warning: decimal constant is so large that it is unsigned
[snip]
Another option is:
int x = INT_MIN;
after #include <limits.h>
Off-by-one? From my limits.h

#define INT_MAX 2147483647
#define INT_MIN (-2147483647-1)

I don't see an off-by-one error. The OP wanted to initialize x to the
value -2147483648. If INT_MIN is defined as above, then
int x = INT_MIN;
is one correct way to do that.

(Two's-complement representations generally do have an extra negative
value.)
 
K

Keith Thompson

James Kuyper said:
No, -2147483648U is an expression containing the unary '-' operator
acting on an unsigned integer; the result will therefore also have an
unsigned integer type, and therefore a positive value.

I'll assume in the following that:
INT_MIN is -2147483648
INT_MAX is 2147483647
UINT_MAX is 4294967295
The numbers above represent numeric values, not necessarily valid C
expressions.

Specifically, given the above assumtions, -2147483648U will have the
value 2147483648U. Negating an unsigned value is equivalent to
subtracting that value from the maximum value of the type plus one.
(For the same reason, -1U has the value 4294967295U.)

If you use the value 2147483648U to initialize an object of type int,
the value must be converted from unsigned int to int. Since the
numeric value 2147483648 is too be to be stored in an int, the result
is implementation-defined (or, in C99, an implementation-defined
signal might be raised). In other words, don't do this if you care
about the portability of your code.

(On a typical two's-complement implementation, converting 2147483648U
to int yields the int value -2147483648, which is exactly what you
want -- but it's not guaranteed by the language, which is why the
compiler is warning you about it.)
Yes, that is the reason. When the mathematical value of INT_MIN is
-2147483648, the C expression (-2147483647-1) is one of the simplest
expressions that has that value.

Right.
 
?

=?iso-2022-kr?q?Harald_van_D=0E=29=26=0Fk?=

Joe Wright said:
CBFalconer said:
kerravon wrote:
The following C program:

int main(void) {
int x = -2147483648;
return (0);
}

Produces the following warning:

temp.c: In function `main':
temp.c:3: warning: decimal constant is so large that it is unsigned
[snip] [un-snip]
The expression consists of the positive integer 2147483648 and a
negation. The positive integer doesn't fit. You can form the
value with "-2147483648 - 1" on 32 bit systems. On 16 bit (or 31
bit, etc.) systems you will need to use a long.
[end un-snip]

Off-by-one?

I don't see an off-by-one error.

The value can be formed with -2147483647 - 1, not -2147483648 - 1.
 
B

Bartc

Yes, that is the reason. When the mathematical value of INT_MIN
is -2147483648, the C expression (-2147483647-1) is one of the simplest
expressions that has that value.

Is it not possible to use a hex constant such as 0x80000000? Would that be
treated as a bit-pattern that includes the sign bit?

Bart
 
K

Keith Thompson

Harald van D)&k said:
Joe Wright said:
CBFalconer wrote: [snip]
The expression consists of the positive integer 2147483648 and a
negation. The positive integer doesn't fit. You can form the
value with "-2147483648 - 1" on 32 bit systems. On 16 bit (or 31
bit, etc.) systems you will need to use a long.
[end un-snip]

Off-by-one?

I don't see an off-by-one error.

The value can be formed with -2147483647 - 1, not -2147483648 - 1.

D'oh! You're right; I misread the "-2147483647 - 1"" in CBFalconer's
post as ""-2147483647 - 1".
 
K

Keith Thompson

Bartc said:
Is it not possible to use a hex constant such as 0x80000000? Would that be
treated as a bit-pattern that includes the sign bit?

A hexadecimal constant doesn't specify a bit pattern; it specifies a
*value*, just as a decimal constant does. The rules for determining
the type vary somewhat for decimal vs. hexadecimal (and for C90
vs. C99).

In C99, the type of a hexadecimal constant is the first of:
int
unsigned int
long int
unsigned long int
long long int
unsigned long long int
which can hold the value. For 0x80000000, assuming 32-bit int, the
result is unsigned int, which creates the same conversion problems as
2147483648U or -2147483648U.

In C90, the sequence is the same except for the omission of long long
int and unsigned long long int, which don't affect this case.
 
J

Joe Wright

Keith said:
Joe Wright said:
CBFalconer said:
kerravon wrote:
The following C program:

int main(void) {
int x = -2147483648;
return (0);
}

Produces the following warning:

temp.c: In function `main':
temp.c:3: warning: decimal constant is so large that it is unsigned [snip]
Another option is:
int x = INT_MIN;
after #include <limits.h>
Off-by-one? From my limits.h

#define INT_MAX 2147483647
#define INT_MIN (-2147483647-1)

I don't see an off-by-one error. The OP wanted to initialize x to the
value -2147483648. If INT_MIN is defined as above, then
int x = INT_MIN;
is one correct way to do that.

(Two's-complement representations generally do have an extra negative
value.)
Chuck suggested "-2147483648 - 1" which is 'off-by-one' I'd say.
 
C

CBFalconer

Keith said:
Harald van D)&k said:
Keith said:
CBFalconer wrote: [snip]
The expression consists of the positive integer 2147483648 and a
negation. The positive integer doesn't fit. You can form the
value with "-2147483648 - 1" on 32 bit systems. On 16 bit (or 31
bit, etc.) systems you will need to use a long.
[end un-snip]

Off-by-one?

I don't see an off-by-one error.

The value can be formed with -2147483647 - 1, not -2147483648 - 1.

D'oh! You're right; I misread the "-2147483647 - 1"" in CBFalconer's
post as ""-2147483647 - 1".

One lousy type has generated at least 3, probably more, discussion
messages. 7 != 8. :)
 
J

Jack Klein

Except C has no negative literals. Your initializer is an expression:
the unary negation operator is applied to a constant. That constant,
2147483648, is indeed so large that it is unsigned (in C90). Negating
this large unsigned number provokes, technically, integer overflow.

No, arithmetic on unsigned types never overflows. The result of
negating an unsigned integer has a well-defined result, namely
UINT_MAX - value.

If that value is outside the range of a signed int and used to
initialize one, the result is implementation-defined.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.club.cc.cmu.edu/~ajo/docs/FAQ-acllc.html
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,994
Messages
2,570,222
Members
46,809
Latest member
moe77

Latest Threads

Top