🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.std.c
Article #3743

Re: Semantics of relational operators

#3743
From: Mark Brader
Date: Wed, 16 Aug 1995 14:30
111 lines
4903 bytes
raine@ferndown.ate.slb.com writes:
> gcc issues the diagnostic "Semantics of <= have changed in ANSI C, please 
> use explicit cast" for the following:
> 
>   unsigned short a = 0;
>   long b = 0;
>   if (a <= b)   /* gcc expects explicit cast here */
> 
> 6.3.8 seems to yield no information as to why a cast is desirable here.

The proper reference is to section 3.2.1.1 of the Rationale, corresponding
to 6.2.1.1 in the renumbered Standard.

I posted the following to comp.lang.c in August:

|  > A C compiler gives for the statement
|  >      if (strlen (...) > 41) ...
|  > the warning
|  >      semantics of ">" change in ANSI C: use explicit cast
|  >  
|  > What does that mean?
|  
|  It means that the compiler is too stupid to tell that the expression 41,
|  despite its type being int, could not possibly be negative.  Ignore it.

In raine's example, though, there could be a real difference if short is
narrower% than int and b < 0.
  
|  In a situation like THIS:
|  
|  	extern unsigned short usvar;
|  	extern int ivar;
|  
|  	if (usvar > ivar)                                /* A */
|  
|  the change would be important.  The type "unsigned short" did not exist
|  in K&R C, and when it was added to the language, different implementers
|  made different choices as to whether to treat the above like
|  
|  	if ((unsigned int) usvar > (unsigned int) ivar)  /* U */
|  or like
|  	if ((int) usvar > (int) ivar)                    /* V */
|  
|  which of course will have different results of ivar is negative.
|  
|  If int and short are the same width%, interpretation U always applies.
|  But if int is wider than short, there are reasons for each choice;
|  The common UNIX compilers for such machines followed interpretation U
|  ("unsigned preserving"), but other compilers followed interpretation V
|  ("value preserving").
|  
|  When the ANSI C standard was written, its writers chose value preserving.
|  Thus, the meaning of code like A changed for people who had been used
|  to unsigned preserving.  They also specified that strlen(), which had
|  returned int on most implementations, should now return size_t, which is
|  some unsigned integer type.  Thus, code that formerly was not like A,
|  but which used strlen(), became like it -- something that likely would
|  not have been feasible if they had chosen unsigned preserving.

In raine's example,

>   unsigned short a = 0;
>   long b = 0;
>   if (a <= b)   /* gcc expects explicit cast here */

if short is narrower% than int, then under the value preserving rules,
a will be promoted to int, then converted to long to match b, and the
comparison will be done in signed arithmetic.  If short is the same
width% as int, then a will be converted to unsigned int, both a and
b will be converted to unsigned long, and the conversion will be done
in unsigned arithmetic.  The latter conversions also apply if unsigned
preserving is in effect.

If b >= 0, the variation makes no difference.  If b < 0, only value
preserving arithmetic has a chance of comparing the actual values of
the variables, though even it might not do so, depending on their sizes;
and this is the ANSI C "change" from unsigned preserving implementations.

If you actually want the comparison in signed arithmetic, use

	if ((long) a <= b)

If you actually want unsigned arithmetic, use a cast to unsigned long.

|  The compiler's warning, then, is a misguidedly terse attempt to warn
|  you about all this.
|  
|  Incidentally, it wasn't only < whose semantics were standardized on
|  value preserving in ANSI C.  Almost all operators are affected.  In
|  particular, an expression like
|  
|  	ivar + usvar
|  
|  was previously ambiguous in the same way and has been resolved in the
|  same way.  This means that that compiler logically ought to give you
|  the same meaningless warning in the case of
|  
|  	strlen (s) + 41
|  
|  as it does for the original line -- semantics of "+" have changed...
|  I bet it doesn't, though.

% - This is a slight simplification, because I don't want to reactivate
the debate about bits not participating in a value.

-- 
Mark Brader   | "A standard is established on sure bases, not capriciously
msb@sq.com    |  but with the surety of something intentional and of a logic
SoftQuad Inc. |  controlled by analysis and experiment.  ... A standard is
Toronto       |  necessary for order in human effort."       -- Le Corbusier
This article is in the public domain.
Technical Details
Message-ID: <1995Aug16.143035.3322@sq.com>
Path: arc1-ca.pugleaf.net!howland.reston.ans.net!torn!sq!msb
References: <40ses9$5o6@sndsu1.sedalia.sinet.slb.com>

Show Full Headers
Complete Article Headers
Newsgroups: comp.std.c
Path: arc1-ca.pugleaf.net!howland.reston.ans.net!torn!sq!msb
From: msb@sq.com (Mark Brader)
Subject: Re: Semantics of relational operators
Message-ID: <1995Aug16.143035.3322@sq.com>
Organization: SoftQuad Inc., Toronto, Canada
References: <40ses9$5o6@sndsu1.sedalia.sinet.slb.com>
Date: Wed, 16 Aug 1995 14:30:35 GMT