does 0<(unsigned short)0x8000 hold?

F

Francois Grieu

I just tested my code for portability problems on systems
where int is 16-bit, and found one such system where

#include <stdio.h>
int main(void)
{
printf("%d\n", 0<(unsigned short)0x8000 );
return 0;
}

outputs 0. If I change 0< to 0u<, the output is 1.

Is that a bug in this compiler, w.r.t. C99?


As an aside, 6.5.8p2 puzzles me; it reads:
"One of the following shall hold:
— both operands have real type;
— both operands are pointers to qualified or unqualified versions
of compatible object types; or
— both operands are pointers to qualified or unqualified versions
of compatible incomplete types.
(..)"

Would my example imply conversion to *real*, at least conceptually ?!

As an aside of the aside, I do not understand the third option in
the constraint, and it has been removed in N1570.

TIA,

Francois Grieu
 
H

Harald van Dijk

I just tested my code for portability problems on systems
where int is 16-bit, and found one such system where

#include <stdio.h>
int main(void)
        {
        printf("%d\n", 0<(unsigned short)0x8000 );
        return 0;
        }

outputs 0. If I change 0< to 0u<, the output is 1.

Is that a bug in this compiler, w.r.t. C99?

unsigned short promotes to int if all values can be represented in
int, otherwise it promotes to unsigned int (6.3.1.1p2), so yes, that
looks like a bug.
As an aside, 6.5.8p2 puzzles me; it reads:
"One of the following shall hold:
 — both operands have real type;
 — both operands are pointers to qualified or unqualified versions
   of compatible object types; or
 — both operands are pointers to qualified or unqualified versions
   of compatible incomplete types.
(..)"

Would my example imply conversion to *real*, at least conceptually ?!

Integer types and floating point types are together called real types
(6.2.5p17); yes, there is an implicit conversion to a real type, and
that type is unsigned int.
As an aside of the aside, I do not understand the third option in
the constraint, and it has been removed in N1570.

It seems to allow comparisons between two void * values, or between
two int(*)[] values. It seems silly to allow that but not also allow a
comparison between f.e. a void * and a char *, but I'm not sure why it
was removed entirely.
 
J

James Kuyper

I just tested my code for portability problems on systems
where int is 16-bit, and found one such system where

#include <stdio.h>
int main(void)
{
printf("%d\n", 0<(unsigned short)0x8000 );
return 0;
}

outputs 0. If I change 0< to 0u<, the output is 1.

Is that a bug in this compiler, w.r.t. C99?

INT_MAX is allowed to be as low as 0x7FFF, and that's presumably true on
a 16-bit system (though there's always been a lot of debate about what
"N-bit system" really means). If so, conversion of (unsigned
short)0x8000 to int would produce a negative value unless int has a
sign-and-magnitude type. But if INT_MAX is 0x7FFF, then (unsigned
char)0x8000 must be promoted to "unsigned int", rather than "int"
(6.3.1.1p2), and therefore 0 must also be converted to unsigned int,
before evaluating the expression. As a result that expression would be
equivalent to 0U < 0x8000U, which is still guaranteed to have a value of
1. I'd say this is a bug in the compiler.
As an aside, 6.5.8p2 puzzles me; it reads:
"One of the following shall hold:
— both operands have real type;
— both operands are pointers to qualified or unqualified versions
of compatible object types; or
— both operands are pointers to qualified or unqualified versions
of compatible incomplete types.
(..)"

Would my example imply conversion to *real*, at least conceptually ?!

"The integer and real floating types are collectively called
real types." (6.2.5p17), therefore no conversion to a real type is
required. As a result, the usual arithmetic conversions require that the
integer promotions be applied to both operands (6.3.1.8p1).
As an aside of the aside, I do not understand the third option in
the constraint, ...

You're referring to "both operands [of a relational operator] are
pointers to qualified or unqualified versions of compatible incomplete
types."? I think the trickiest concept used in that sentence is
"pointers to ... compatible incomplete types". Is that what you're
having trouble with? Each of the following declarations defines a
pointer to an incomplete type:

int (*p_incomplete_array)[];
struct flexible_array
{
size_t count;
int member[];
} *pfa;
// No definition provided for struct my_struct
struct my_struct *pms;
void *pv;
... and it has been removed in N1570.

I can confirm that it has been removed. The implication would seem to be
that it's no longer possible to compare pointers to incomplete types for
relative order. I find this surprising. Am I misunderstanding it? If not
was it deliberately removed, or an accident? If deliberate, what was the
rationale for doing so?
 
B

Ben Bacarisse

Francois Grieu said:
I just tested my code for portability problems on systems
where int is 16-bit, and found one such system where

#include <stdio.h>
int main(void)
{
printf("%d\n", 0<(unsigned short)0x8000 );
return 0;
}

outputs 0. If I change 0< to 0u<, the output is 1.

Is that a bug in this compiler, w.r.t. C99?

It looks wrong to me. GCC says 1 on my machine and that's what I'd
expect.
As an aside, 6.5.8p2 puzzles me; it reads:
"One of the following shall hold:
— both operands have real type;
— both operands are pointers to qualified or unqualified versions
of compatible object types; or
— both operands are pointers to qualified or unqualified versions
of compatible incomplete types.
(..)"

Would my example imply conversion to *real*, at least conceptually ?!

Depends on what "conceptually" means here! 6.2.5 p 17 says:

The type char, the signed and unsigned integer types, and the
enumerated types are collectively called integer types. The integer
and real floating types are collectively called real types.

so it's really just a catch-all term like arithmetic type.
As an aside of the aside, I do not understand the third option in
the constraint, and it has been removed in N1570.

It makes sense to remove it. You can compare two pointers to incomplete
types for equality, but <, >, etc are defined in terms of sub-objects in
a array, so only pointers to object type make good sense.

Some previously well-defined code (albeit not very useful code) will now
require a diagnostic.
 
F

Francois Grieu

(..) that expression would be equivalent to 0U < 0x8000U (..)

I get to that also. It is a bug in the compiler. Main question solved.

"The integer and real floating types are collectively called
real types." (6.2.5p17),

Ah! First aside solved. I read "real" and understood "floating".
(..) I think the trickiest concept used in that sentence is
"pointers to ... compatible incomplete types". Is that what you're
having trouble with?
Yes.

Each of the following declarations defines a
pointer to an incomplete type:

int (*p_incomplete_array)[];
struct flexible_array
{
size_t count;
int member[];
} *pfa;
// No definition provided for struct my_struct
struct my_struct *pms;
void *pv;

Ah, thanks for the illustration! Now I see 6.2.5p1, defining
"incomplete type" as one of "types that describe objects but lack
information needed to determine their sizes".
So when I'm using a pointer to void, I'm using an "incomplete type",
like Mr. Jourdain is using prose [I choose to never use the other
forms, for portability].
I can confirm that it has been removed. The implication would seem to be
that it's no longer possible to compare pointers to incomplete types for
relative order. I find this surprising. Am I misunderstanding it? If not
was it deliberately removed, or an accident? If deliberate, what was the
rationale for doing so?

Indeed, comparing pointers to void referring to elements in the same
struct or array seems like a feature that could help on occasions, was
OK in C99, and seems gone from C2011 for no apparent reason. I second
the question.

Francois Grieu
 
T

Tim Rentsch

Francois Grieu said:
I just tested my code for portability problems on systems
where int is 16-bit, and found one such system where

#include <stdio.h>
int main(void)
{
printf("%d\n", 0<(unsigned short)0x8000 );
return 0;
}

outputs 0. If I change 0< to 0u<, the output is 1.

Is that a bug in this compiler, w.r.t. C99?

Yes. There is a simple argument that it is:

1. The value 0x8000 is always representable as an unsigned short.

2. The rules for 'integer promotions' always preserve value.

3. The rules for 'usual arithmetic conversions' preserve value
for all operand values that are non-negative. (A negative
operand value might become non-negative due to UAC, but
all non-negative values don't change under UAC.)

Since 0 < 0x8000 must hold, 0 < (unsigned short) 0x8000 must hold,
because ultimately the same mathematical comparison is done.

As an aside, 6.5.8p2 puzzles me; [snip]

As an aside of the aside, I do not understand the third option in
the constraint, and it has been removed in N1570.

The removal is not a change but just indicative of a change in
nomenclature. In C99, there are incomplete types and object
types. In N1570, there are incomplete object types and complete
object types, which together make up object types. So in N1570,
both complete and incomplete types are included under the now
more general 'object type' term, and hence the third option in
C99 is folded into the second option in N1570.
 
B

Ben Bacarisse

Ben Bacarisse said:
Francois Grieu <[email protected]> writes:

It makes sense to remove it.

No it didn't! This part of my reply was nonsense. It's perfectly
possible to well-define relative comparisons between pointers to
incomplete types.

It's good to see that the change is just due to a change in terminology.
 
J

James Kuyper

No it didn't! This part of my reply was nonsense. It's perfectly
possible to well-define relative comparisons between pointers to
incomplete types.

It's good to see that the change is just due to a change in terminology.

Could you explain the change in terminology? I thought about the
possibility that something like that was involved, but I didn't notice
anything relevant.
 
H

Harald van Dijk

Could you explain the change in terminology? I thought about the
possibility that something like that was involved, but I didn't notice
anything relevant.

I didn't notice it either, but as Tim Rentsch pointed out, the change
is in 6.2.5p1.

Old: "Types are partitioned into object types (types that fully
describe objects), function types (types that describe functions), and
incomplete types (types that describe objects but lack information
needed to determine their sizes)."

New: "Types are partitioned into object types (types that describe
objects) and function types (types that describe functions)."
 
J

James Kuyper

I didn't notice it either, but as Tim Rentsch pointed out, the change
is in 6.2.5p1.

Ah - that explains why I didn't know what Ben was talking about. I've
got Tim killfiled - not because he's a spammer or any other kind of
idiot, but just because I found that I frequently ended up wasting lots
of time in long discussions with him disagreeing about excessively
subtle issues without either of us ever managing to change the mind of
the other. That would not have mattered if the discussions had been fun,
or at least interesting, but I just found them frustrating - which could
just as easily have been my fault as his.
 
F

Francois Grieu

Yes. There is a simple argument that it is:

1. The value 0x8000 is always representable as an unsigned short.

2. The rules for 'integer promotions' always preserve value.

3. The rules for 'usual arithmetic conversions' preserve value
for all operand values that are non-negative. (A negative
operand value might become non-negative due to UAC, but
all non-negative values don't change under UAC.)

Since 0 < 0x8000 must hold, 0 < (unsigned short) 0x8000 must hold,
because ultimately the same mathematical comparison is done.

Nice, reusable argument. Thanks.
As an aside, 6.5.8p2 puzzles me; [snip]

As an aside of the aside, I do not understand the third option in
the constraint, and it has been removed in N1570.

The removal is not a change but just indicative of a change in
nomenclature. In C99, there are incomplete types and object
types. In N1570, there are incomplete object types and complete
object types, which together make up object types. So in N1570,
both complete and incomplete types are included under the now
more general 'object type' term, and hence the third option in
C99 is folded into the second option in N1570.

Again, thanks for the synthetic explanation.

Francois Grieu
 
F

Francois Grieu

I just tested my code for portability problems on systems
where int is 16-bit, and found one such system where […]

Which system?

The CPU was a regular PC, running cmd.exe of Windows XP SP3; the
failing compiler was Turbo C++ 1.01 (released 1991) in C mode.
I am NOT using that compiler for anything but test.
I there is a more modern 80x86 16-bit compiler (defined as
UINT_MAX==0xFFFF, perhaps as an option), I want to know.

My usual 16-bit targets include
- ST7/ST19/ST21/ST23
- PIC18
- 8051 and derivatives
and (at least with the compilers I now use for production)
pass this test.

My customer's platform include
- 68K derivatives (including ColdFire)
- ARM derivatives
- MIPS derivatives
- 80x86 derivatives
For some of my customer's target systems, the option exist
to compile with a 16-bit int (e.g. gcc -mshort ), and I have
no idea of my customer's choice.

Francois Grieu
 
K

Kaz Kylheku

I just tested my code for portability problems on systems
where int is 16-bit, and found one such system where […]

Which system?

The CPU was a regular PC, running cmd.exe of Windows XP SP3; the
failing compiler was Turbo C++ 1.01 (released 1991) in C mode.

Hahaha, you wasted everyone's time answering questions about
irrelevant old cruft. Good job!
 

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
474,260
Messages
2,571,039
Members
48,768
Latest member
first4landlord

Latest Threads

Top