0x400000*3/0x40000 undefined ?

F

Francois Grieu

A true story: one C compiler for an embedded processor that
I use claims " ANSI '89 compatibility ". But when I upgraded
from version 2.30 to 2.30.01, some previously working code
misbehaved. After reduction, it turns out that for

unsigned char foo = 0x400000*3/0x40000;

the former compiler set foo to 0x30, and the later 0xF0.

All versions of the compiler agree on
foo = 0x400000*3L/0x40000; /* 0x30 */
foo = 0xC00000/0x40000; /* 0x30 */
foo = 0x400000*3>>18; /* 0x30 */
foo = 0x40000*3/0x4000; /* 0x30 */

The outcome of <limits.h> is that
INT_MAX is 32767
LONG_MAX is 0x7fffffff
but it turns out the compiler has a an extra non-standard
"short long" integer type, and
SLONG_MAX is 0x7fffff

Is the newer compiler wrong ?


Francois Grieu
 
K

Keith Thompson

Francois Grieu said:
A true story: one C compiler for an embedded processor that
I use claims " ANSI '89 compatibility ". But when I upgraded
from version 2.30 to 2.30.01, some previously working code
misbehaved. After reduction, it turns out that for

unsigned char foo = 0x400000*3/0x40000;

the former compiler set foo to 0x30, and the later 0xF0.

All versions of the compiler agree on
foo = 0x400000*3L/0x40000; /* 0x30 */
foo = 0xC00000/0x40000; /* 0x30 */
foo = 0x400000*3>>18; /* 0x30 */
foo = 0x40000*3/0x4000; /* 0x30 */

The outcome of <limits.h> is that
INT_MAX is 32767
LONG_MAX is 0x7fffffff
but it turns out the compiler has a an extra non-standard
"short long" integer type, and
SLONG_MAX is 0x7fffff

Is the newer compiler wrong ?

Yes, I believe it is.

Adding a "short long" type should be ok, since it can only be used by
a program that would be illegal in strict ANSI mode.

Adding SLONG_MAX to <limits.h> is non-conforming, but it's not going
to be a problem unless the user program tries to define that
identifier for itself.

But I think the real problem is that it treats the hex constants as
being of type "short long".

The type of a hex constant is the first of
int
unsigned int
long
unsigned long
in which its value will fit (C99 adds long long and unsigned long
long). In this case, both 0x400000 and 0x40000 should be of type
long. Apparently the compiler chooses to treat them as constants of
type "short long", which would make perfect sense if "short long" were
part of the language.

On the other hand, the declaration

unsigned char foo = 0x400000*3/0x40000;

is non-portable, and would legitimately yield the same result if
INT_MAX were 0x7fffff. It might be better to specify the types
explicitly:

unsigned char foo = 0x400000UL*3/0x40000UL;

or simply:

unsigned char foo = 0x30;

if that's what you want. (The latter probably doesn't apply, since
you said it was the result of reducing the actual code.)
 
C

CBFalconer

Francois said:
A true story: one C compiler for an embedded processor that
I use claims " ANSI '89 compatibility ". But when I upgraded
from version 2.30 to 2.30.01, some previously working code
misbehaved. After reduction, it turns out that for

unsigned char foo = 0x400000*3/0x40000;

the former compiler set foo to 0x30, and the later 0xF0.

All versions of the compiler agree on
foo = 0x400000*3L/0x40000; /* 0x30 */
foo = 0xC00000/0x40000; /* 0x30 */
foo = 0x400000*3>>18; /* 0x30 */
foo = 0x40000*3/0x4000; /* 0x30 */

The outcome of <limits.h> is that
INT_MAX is 32767
LONG_MAX is 0x7fffffff
but it turns out the compiler has a an extra non-standard
"short long" integer type, and
SLONG_MAX is 0x7fffff

Is the newer compiler wrong ?

Yes, it is broken. However you can and should have simply used 3L
in the original expression. Without checking limits.h you have no
idea what type 0x400000 actually is.
 
O

Old Wolf

Francois said:
A true story: one C compiler for an embedded processor that
I use claims " ANSI '89 compatibility ". But when I upgraded
from version 2.30 to 2.30.01, some previously working code
misbehaved. After reduction, it turns out that for

unsigned char foo = 0x400000*3/0x40000;

the former compiler set foo to 0x30, and the later 0xF0.

All versions of the compiler agree on
foo = 0x400000*3L/0x40000; /* 0x30 */
foo = 0xC00000/0x40000; /* 0x30 */
foo = 0x400000*3>>18; /* 0x30 */
foo = 0x40000*3/0x4000; /* 0x30 */

The outcome of <limits.h> is that
INT_MAX is 32767
LONG_MAX is 0x7fffffff
but it turns out the compiler has a an extra non-standard
"short long" integer type, and
SLONG_MAX is 0x7fffff


Clearly this compiler is treating 0x400000 as a SLONG
which then overflows when you multiply it by 3
(probably giving you a negative number).
Is the newer compiler wrong ?

Obviously. You should disable this slong extension,
unless you really need the optimisation .
You could also avoid troubles by labelling your long
constants as long: 0x400000L * 3 / 0x40000
Some compilers can display a warning if you use a long
constant without specifying the L suffix etc.

Ideally there would be a compiler switch to disable it
for unadorned integer constants and integer promotions,
but allow you to explicity specify a 'slong' . That
way, ANSI compliant code could still be compiled. I am
afraid that if there is no switch then you will have to
review all of your code for integer promotions to slong.
 
C

Christian Bau

Francois Grieu said:
A true story: one C compiler for an embedded processor that
I use claims " ANSI '89 compatibility ". But when I upgraded
from version 2.30 to 2.30.01, some previously working code
misbehaved. After reduction, it turns out that for

unsigned char foo = 0x400000*3/0x40000;

the former compiler set foo to 0x30, and the later 0xF0.

All versions of the compiler agree on
foo = 0x400000*3L/0x40000; /* 0x30 */
foo = 0xC00000/0x40000; /* 0x30 */
foo = 0x400000*3>>18; /* 0x30 */
foo = 0x40000*3/0x4000; /* 0x30 */

The outcome of <limits.h> is that
INT_MAX is 32767
LONG_MAX is 0x7fffffff
but it turns out the compiler has a an extra non-standard
"short long" integer type, and
SLONG_MAX is 0x7fffff

Is the newer compiler wrong ?

It seems that you use a compiler for a language that is similar to C,
but not equal to C. I would say that your compiler is right, but it is
not a C compiler :-(

(Obviously a completely conforming compiler that used 24 bit int's could
also give the results that you found, so the code was never 100%
portable in the first place).
 
P

Peter Nilsson

Francois said:
A true story: one C compiler for an embedded processor that
I use claims " ANSI '89 compatibility ". But when I upgraded
from version 2.30 to 2.30.01, some previously working code
misbehaved. After reduction, it turns out that for

unsigned char foo = 0x400000*3/0x40000;

This in itself is not strictly conforming.
the former compiler set foo to 0x30, and the later 0xF0.

All versions of the compiler agree on
foo = 0x400000*3L/0x40000; /* 0x30 */
foo = 0xC00000/0x40000; /* 0x30 */
foo = 0x400000*3>>18; /* 0x30 */
foo = 0x40000*3/0x4000; /* 0x30 */

Other replies notwithstanding, the first alternative above is better
than the original.

Your original code can still fail on genuine conforming compilers since
0x400000 may be an int, but 0x400000*3 may (theoretically) overflow. By
forcing the use of longs (or unsigned longs) you give strict
conformance to your code (for the given constants.)
 
J

Jack Klein

It seems that you use a compiler for a language that is similar to C,
but not equal to C. I would say that your compiler is right, but it is
not a C compiler :-(

(Obviously a completely conforming compiler that used 24 bit int's could
also give the results that you found, so the code was never 100%
portable in the first place).

Yes, and there were (and probably still are) such compilers for the
Motorola 56xxx series of Digital Signal Processors. The original
members of the family had 24-bit registers, 24-bit ints, and 48-bit
longs.
 
F

Francois Grieu

Thanks for all the comments. I agree with most, and especially
with Christian Bau's
I would say that your compiler is right, but it is
not a C compiler :-(


François Grieu
 

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

No members online now.

Forum statistics

Threads
473,780
Messages
2,569,611
Members
45,280
Latest member
BGBBrock56

Latest Threads

Top