[net.lang.c] conversion of short to unsigned it

wescott@ncrcae.UUCP (Mike Wescott) (03/17/85)

What's the proper conversion of a short to an unsigned int?
In otherwords should the conversion be a sign extension of the
short treated as an unsigned int after sign extension, or should
there be no sign extension?

Does K&R say anything?

How about the draft C standard?

What's your feeling?

ndiamond@watdaisy.UUCP (Norman Diamond) (03/19/85)

> What's the proper conversion of a short to an unsigned int?
> In otherwords should the conversion be a sign extension of the
> short treated as an unsigned int after sign extension, or should
> there be no sign extension?

(int) (unsigned) x   does not necessarily equal   (unsigned) (int) x

-- 

   Norman Diamond

UUCP:  {decvax|utzoo|ihnp4|allegra}!watmath!watdaisy!ndiamond
CSNET: ndiamond%watdaisy@waterloo.csnet
ARPA:  ndiamond%watdaisy%waterloo.csnet@csnet-relay.arpa

"Opinions are those of the keyboard, and do not reflect on me or higher-ups."

darryl@ISM780.UUCP (03/20/85)

[Stop me before I quote again!]

K&R, page 184, section 6.6, "Arithmetic Conversions":

    "A great many operators cause conversions and yield result types in
a similar way.  This pattern will be called the "usual arithmetic
conversions".

    "First, any operands of type char or short are converted to int, and any
of type float are converted to double.
	:
	:
	:
    "Otherwise, if either operand is unsigned, the other is converted to
unsigned and that is the type of the result.
	:
	:
	:

The new version of the C reference manual supplied with system V changes
the results in the case of long x unsigned;  in K&R, this results in a long,
but now it is an unsigned long (is there any real difference?).

	    --Darryl Richman, INTERACTIVE Systems Corp.
	    ...!cca!ima!ism780!darryl
	    The views expressed above are my opinions only.

wescott@ncrcae.UUCP (Mike Wescott) (03/21/85)

The motivation for the original posting on this question, (which I belatedly
canceled so as to make a more reasoned submission), is an inconsistency in
the C-compiler concerning the conversion of short to unsigned int.  Both
SYsVr2 and 4.2BSD compilers exhibit the inconsistency:

	unsinged int ui;
	unsigned short us;
	short s;
	   .
	   .
	   .
	s = -3;
	us = -3;
	ui = s;
	printf("%x %x %x\n", ui, us, s);

prints
fffffffd fffd fffffffd
as expected.  However the comparison 

	if ((unsigned int)s == us) printf("OOPS\n");

prints OOPS meaning that fffffffd == 0000fffd !!!
The code generated for the comparison is a

	cmpw	_s, _us

No conversion.  K&R confused me with the "otherwise" phrase
in the section on arithmetic conversions.  The version of the C standard
was not much more help but it eventually became clear that the code for
the comparison is improperly generated.  The short should be sign extend
and the unsigned short should be padded with 0's on the left and the
compare should be a cmpl.

The piece of code that brought this to light was SysVr2's uucp code in
pk0.c/chksum(), where the code

	register short sum;
	register unsigned short t;
	    .
	    .
	    .
	if ((unsigned)sum <= t) {
	    .
	    .
	    .
"broke" on a new compiler.  Explicitly casting to "unsigned short" fixed
the checksum calculation (i.e. made uucp talk to our vax).  Looking
at the code generated on the vax pointed up the inconsistency.

BTW, the cast (unsigned) implies (unsigned int), and the vax C-compiler
produces a cmpw for both casts.

	Mike Wescott
	NCR Corp.
	ncrcae!wescott

ndiamond@watdaisy.UUCP (Norman Diamond) (03/22/85)

> 	unsinged int ui;
> 	unsigned short us;
> 	short s;
>
> 	s = -3;
> 	us = -3;
> 	ui = s;
>
> 	if ((unsigned int)s == us) printf("OOPS\n");
>
> prints OOPS meaning that fffffffd == 0000fffd !!!

It could mean 0000fffd == 0000fffd.
If (unsigned int) s is sometimes equivalent to (unsigned int) (int) s,
but other times equivalent to (unsigned int) (unsigned short) s,
then I don't think any rule is being violated.  A compiler does not
have to be consistent in its treatment of ambiguous constructs.
(In fact, inconsistency should be encouraged because it quickens the
discovery of bugs.)

-- 

   Norman Diamond

UUCP:  {decvax|utzoo|ihnp4|allegra}!watmath!watdaisy!ndiamond
CSNET: ndiamond%watdaisy@waterloo.csnet
ARPA:  ndiamond%watdaisy%waterloo.csnet@csnet-relay.arpa

"Opinions are those of the keyboard, and do not reflect on me or higher-ups."

ken@turtlevax.UUCP (Ken Turkowski) (03/24/85)

In article <2128@ncrcae.UUCP> wescott@ncrcae.UUCP (Mike Wescott) writes:
>	unsigned short us;
>	short s;
>	   .
>	   .
>	   .
>	s = -3;
>	us = -3;
>	ui = s;
 ...
>
>	if ((unsigned int)s == us) printf("OOPS\n");
>
>prints OOPS meaning that fffffffd == 0000fffd !!!
>The code generated for the comparison is a
>
>	cmpw	_s, _us
>
>No conversion.  K&R confused me with the "otherwise" phrase
>in the section on arithmetic conversions.  The version of the C standard
>was not much more help but it eventually became clear that the code for
>the comparison is improperly generated.  The short should be sign extend
>and the unsigned short should be padded with 0's on the left and the
>compare should be a cmpl.

I disagree.  The "(unsigned int)" is a cast, saying that s is to be
considered unsigned rather than signed.  It is NOT a conversion.  The
fact that s was declared to be a "short int" is immaterial; it is of
type int rather than float, etc.  This has the same effect as saying
"(unsigned)", without the "int".  Int has no inherent size associated
with it; the size of an int is machine-dependent.  If you want an int
of a specific size, you say "short int" or "long int".

I would suggest that you try the statement

	if ((unsigned long int)s == us) printf("OOPS\n");

instead, and see if you get the same results.  This explicitly
specifies a size conversion.

-- 

Ken Turkowski @ CADLINC, Menlo Park, CA
UUCP: {amd,decwrl,hplabs,nsc,seismo,spar}!turtlevax!ken
ARPA: turtlevax!ken@DECWRL.ARPA

ndiamond@watdaisy.UUCP (Norman Diamond) (03/27/85)

>  The "(unsigned int)" is a cast, saying that s is to be
> considered unsigned rather than signed.  It is NOT a conversion.  The
> fact that s was declared to be a "short int" is immaterial; it is of
> type int rather than float, etc.  This has the same effect as saying
> "(unsigned)", without the "int".  Int has no inherent size associated
> with it; the size of an int is machine-dependent.  If you want an int
> of a specific size, you say "short int" or "long int".
> -- Ken Turkowski @ CADLINC, Menlo Park, CA

A cast had better do conversion.  Can you imagine (float) 3 being some
epsilon-ish sort of value?

Can you imagine      char *c;
                     int  *x;

                     x = (int *) c;

not converting from (char *) to (int *) ?  (This is irrelevant on machines
that use char * for all pointers.  If a machine uses byte offsets for char *
... such as calloc still is supposed to return ... and the assignment doesn't
CONVERT the result of calloc to int * ... then we might as well give up with C.)
-- 

   Norman Diamond

UUCP:  {decvax|utzoo|ihnp4|allegra}!watmath!watdaisy!ndiamond
CSNET: ndiamond%watdaisy@waterloo.csnet
ARPA:  ndiamond%watdaisy%waterloo.csnet@csnet-relay.arpa

"Opinions are those of the keyboard, and do not reflect on me or higher-ups."

henry@utzoo.UUCP (Henry Spencer) (03/27/85)

There was a certain vagueness about the definition of casts in the
V7 C reference manual; they were rather new.  In particular, it wasn't
clear whether they caused a conversion or just caused the compiler to
think a conversion had been done.  After some confusion, their semantics
were clarified, and the official word from DMR (and now from the ANSI
committee) is that casting to type foo is equivalent to assigning to a
temporary variable of type foo.  So yes, casts are conversions.
-- 
				Henry Spencer @ U of Toronto Zoology
				{allegra,ihnp4,linus,decvax}!utzoo!henry