[comp.lang.c] Long integers

gtchen@faline.bellcore.com (George T. Chen) (09/11/87)

Has anyone had this problem?

...
   void get_value(size)
   long *size;
   {   ...(do some processing)...
       printf("%ld",*size);
   }

   void routine()
   {   ...(some declarations)...
       long size;
       ...(some other stuff)....
       get_value(&size);
       printf("%ld",size);
   }

This routine dies on me!  (Well not dies but doesn't work)  For some
reason, size is correct in the get_value routine, but seems to be
int(size/256.)*256 in the calling routine.  Almost as if the least
significant byte became 0.  However, if I now change routine to

   void routine()
   {   ...(same declarations)...
       long garbage,size;
       ...(same other stuff)....
       get_value(&size);
       printf("%ld",size);
       garbage = 0;	/* So that garbage is allocated memory instead */
			/* of being ignored by the compiler */
   }

then everything works fine and dandy.  What's going on?  Someone told
me it might be a problem with odd and even bytes, but I don't quite
understand that.  All help appreciated.



-- 
+-----------------------------------------------------------------------------+
|What's a .signature? Life is an equation whose only solutions are irrational |
|gtchen@thumper.bellcore.com ! gtchen@romeo.caltech.edu ! gtchen@where.am.i?. |
+-----------------------------------------------------------------------------+

moss@BRL.ARPA (Gary S. Moss (SLCBR-VL-V)) (09/14/87)

George,
	The format %ld is wrong when using the PRINTF family of functions.
The reason for this is that integer arguments are *always* widened to LONG
when passed in to a function, so the %d format is meant for LONGS.  This
is also true for %f.  I am not certain, but pretty sure that I have gotten
wrong behavior when using %ld in this context on certain hardware.

	This is contrary to the SCANF family where you *need* the %ld because
you are placing the result in an address whose type is not known to the
function.

~moss

ark@alice.UUCP (09/14/87)

In article <9266@brl-adm.ARPA>, moss@BRL.ARPA writes:

> 	The format %ld is wrong when using the PRINTF family of functions.
> The reason for this is that integer arguments are *always* widened to LONG
> when passed in to a function, so the %d format is meant for LONGS.  This
> is also true for %f.  I am not certain, but pretty sure that I have gotten
> wrong behavior when using %ld in this context on certain hardware.

Nope.  Chars and shorts are widened to ints, and floats are widened
to doubles, but ints are not widened to longs.  Thus you should always
use %d for char, short, or int, and %ld for long.

guy@sun.uucp (Guy Harris) (09/15/87)

> 	The format %ld is wrong when using the PRINTF family of functions.
> The reason for this is that integer arguments are *always* widened to LONG
> when passed in to a function, so the %d format is meant for LONGS.

Excuse me, but this is total rubbish.  Arguments *shorter* than "int" are
widened to "int" - NOT "long" - when passed to a function.  "int" arguments
are left alone.

"%d" will NOT work for "long" arguments on a machine where "int" and "long"
are not the same size.  %d is NOT meant for "long"s, it is meant for "int"s.
"%ld" is what you must use for "long"s.
-- 
	Guy Harris
	{ihnp4, decvax, seismo, decwrl, ...}!sun!guy
	guy@sun.com (or guy@sun.arpa)

aeusesef@csun.UUCP (Sean Eric Fagan) (09/15/87)

In article <9266@brl-adm.ARPA> moss@BRL.ARPA (Gary S. Moss (SLCBR-VL-V)) writes:
>George,
>	The format %ld is wrong when using the PRINTF family of functions.
>The reason for this is that integer arguments are *always* widened to LONG
>when passed in to a function, so the %d format is meant for LONGS.  This
>is also true for %f.  I am not certain, but pretty sure that I have gotten
>wrong behavior when using %ld in this context on certain hardware.
>
>~moss

Uhm, I think you're going to get a lot of flack about this, so I'll start
it.  C does *NOT* convert integer arguments to longs unless a)told to (via
(long) typecast or a 'L' at the end of the suffix) or b)needs to because it
is used in an expression where one of the subexpressions is a long (did that
make sense?).  Remember, this all comes from a PDP-11, where having longs
meant extra work for the cpu.  Floats are, however, converted to doubles.
Of course, I could be wrong, but I don't believe so.

 -----

 Sean Eric Fagan          Office of Computing/Communications Resources
 (213) 852 5742           Suite 2600
 1GTLSEF@CALSTATE.BITNET  5670 Wilshire Boulevard
                          Los Angeles, CA 90036
{litvax, rdlvax, psivax, hplabs, ihnp4}!csun!aeusesef
"Tempus fugit AirCal"

henry@utzoo.UUCP (Henry Spencer) (09/15/87)

> 	The format %ld is wrong when using the PRINTF family of functions.
> The reason for this is that integer arguments are *always* widened to LONG
> when passed in to a function, so the %d format is meant for LONGS.

NO NO NO NO NO!!!!

Arguments of type short or int are passed as     int    , not as long!  On
32-bit machines, it usually happens that "int" and "long" are synonymous.
But this is not guaranteed to be true everywhere!  %d is the correct format
for shorts and ints in printf; %ld should always be used for longs.  In
scanf, it's %hd for short, %d for int, %ld for long, no mistakes allowed.

> This is also true for %f.

Here we have slightly different rules:  floats are passed as doubles, so
in printf it is always correct to use %f.  In scanf, once again, it is
necessary to be fussier:  %f for float and %lf for double.

The ANSI C people have added some minor complications to this but have
not changed the basic rules.

If code that follows these rules malfunctions, either the code or the
compiler (or its library) is broken.
-- 
"There's a lot more to do in space   |  Henry Spencer @ U of Toronto Zoology
than sending people to Mars." --Bova | {allegra,ihnp4,decvax,utai}!utzoo!henry

pinkas@cadeos.UUCP (09/15/87)

In article <9266@brl-adm.ARPA> moss@BRL.ARPA (Gary S. Moss (SLCBR-VL-V)) writes:
>George,
>	The format %ld is wrong when using the PRINTF family of functions.
>The reason for this is that integer arguments are *always* widened to LONG
>when passed in to a function, so the %d format is meant for LONGS.  This
>is also true for %f.  I am not certain, but pretty sure that I have gotten
>wrong behavior when using %ld in this context on certain hardware.
>
>	This is contrary to the SCANF family where you *need* the %ld because
>you are placing the result in an address whose type is not known to the
>function.
>
>~moss

Gary,

I believe that you are incorrect.  K&R (p146) states that:

"Each conversion specification is introduced by the character % and ended
by a conversion character.  Between th % and the conversion character there
may be:

...

    A length modifier l (letter ell), which indicates that the
    corresponding data item is a long rater than an int."

The default type for printf is int.  (We are talking about interger data
types here: short, int and long.)  Note that a short is promoted to an int
by rule 6.1 in Appendix A (p183), which states that shorts and chars are
promoted to ints in expressions.

Therefor, the only integer type parameters are int and long.  The %d
conversion corresponds to int and the %ld corresponds to long.  (The o, x,
u and c conversion characters all expent an int.  The e, f, and g
conversion characters all expect a double, as floats are promoted to
doubles by 6.2 (p184).  o, x, and u just treat the int as unsigned.  They
are allowed to as signed and unsigned entities are the same length.)

An interesting thing to note is that in the scanf family, the argument type
must correspond EXACTLY to the conversion character.  Thus, we have that d,
o, and x expect an int; h expects a short; c expects a char; f expects a
float; ld, lo, and lx expect a long; and lf expects a double.

(Some of the above may have been changed in the ANSI standard.  I don't
have my copy of the draft here to look it up.)

So we have that George was probably correct.  (I didn't see his posting.)

Incidentally, on a VAX, ints and longs are interchangeable.  So the l
spcifier is unnecessary for ints.  (It is still necessary for doubles,
though.)  On my IBM-PC, C compilers use 16 bit ints, keeping with the rule
that an int should be "the natural size for the machine, not smaller than a
short, not larger than a long."  So on my PC, I am more aware of int/long
incompatibilities like this.

-Israel

----------------------------------------------------------------------
Disclaimer: The above are my personal opinions, and in no way represent
the opinions of Intel Corporation.  In no way should the above be taken
to be a statement of Intel.

UUCP:	{amdcad,decwrl,hplabs,oliveb,pur-ee,qantel}!intelca!mipos3!pinkas
ARPA:	pinkas%mipos3.intel.com@relay.cs.net
CSNET:	pinkas%mipos3.intel.com

---------
"You can do more with a kind word and a gun than with just a kind word"

			-Al Capone

moss@BRL.ARPA (Gary S. Moss (SLCBR-VL-V)) (09/15/87)

Tim and Raymond,
	Thanks for the correction, you're absolutely right, INT is the
natural size, LONG being longer on many machines, notably 16-bit ones
(It's been a while since I used them).  So, %ld is correct to use with
PRINTF and LONGs.  I must have been thinking of floats, but in any case,
I guess I didn't think very much.  Sorry for the mistake folks.

~moss

smvorkoetter@watmum.UUCP (09/16/87)

In article <9266@brl-adm.ARPA> moss@BRL.ARPA (Gary S. Moss (SLCBR-VL-V)) writes:
>	The format %ld is wrong when using the PRINTF family of functions.
>The reason for this is that integer arguments are *always* widened to LONG

From where did you get this piece of information? Char is always widened to
int, and float to double, but never int to long.

Stefan Vorkoetter
University of Waterloo
Symbolic Computation Group

steve@nuchat.UUCP (09/16/87)

In article <9266@brl-adm.ARPA>, moss@BRL.ARPA (Gary S. Moss) writes:
> George,
> 	The format %ld is wrong when using the PRINTF family of functions.
> The reason for this is that integer arguments are *always* widened to LONG
> when passed in to a function, so the %d format is meant for LONGS.  This
> is also true for %f.  I am not certain, but pretty sure that I have gotten
> wrong behavior when using %ld in this context on certain hardware.

This can't be allowed to stand.  In C, scalar types smaller than an
int are promoted to _int_ when passed to a function, including printf.
Thus there is no need for special provisions for printing shorts or
chars as integers.  But long may be larger than int, which you would
know if you didn't program vax's or vax-alikes, and thus a special
indicator is required for printing longs.

> 	This is contrary to the SCANF family where you *need* the %ld because
> you are placing the result in an address whose type is not known to the
> function.

True. One would also need special indicators for short and char if one
wanted to be able to scanf '%d' into them.

A similar thing happens with floting point: floats and doubles are
passed to printf as double, so only one %f is needed.  But scanf
would have to know which was being pointed to to poke the converted
value properly.
-- 
Steve Nuchia			Of course I'm respectable!  I'm old!
{soma,academ}!uhnix1		Politicians, ugly buildings, and whores
!nuchat!steve			all get respectable if they last long enough.
(713) 334 6720				- John Huston, Chinatown

peter@sugar.UUCP (09/16/87)

In article <9266@brl-adm.ARPA>, moss@BRL.ARPA (Gary S. Moss (SLCBR-VL-V)) writes:
> George,
> 	The format %ld is wrong when using the PRINTF family of functions.

Nope, it's right.

> The reason for this is that integer arguments are *always* widened to LONG
> when passed in to a function, so the %d format is meant for LONGS.

Integer arguments are widened to INT when passed in to a function. If you
always run on Vaxen and 68000s and the like (as you presumably have) you will
never have any problems. If you run on PDP11s and 8086s you'll get the most
amazing results.

> This
> is also true for %f.

This is true for %f, but not for %d. Probably there didn't happen to be any
performance advantage to using the longer floats on a PDP11 and this became
entrenched in the language.

> I am not certain, but pretty sure that I have gotten
> wrong behavior when using %ld in this context on certain hardware.

when either your compiler is wrong or you were really using an integer or
(more likely) a pointer and assuming it was a long. Pointers may be longs
on an 8086, but never are on a PDP11.

The Vandata version of the Whitesmiths 'C' compiler on the 8080 actually
promoted to char (i.e., didn't promote) when passing integers when you were
compiling in the tightest possible mode. This was great for small embedded
systems.
-- 
-- Peter da Silva `-_-' ...!hoptoad!academ!uhnix1!sugar!peter
--                 'U`      ^^^^^^^^^^^^^^ Not seismo!soma (blush)

dave@westmark.UUCP (09/17/87)

In article <9266@brl-adm.ARPA>, moss@BRL.ARPA writes:
> George,
> 	The format %ld is wrong when using the PRINTF family of functions.
> The reason for this is that integer arguments are *always* widened to LONG
> when passed in to a function, so the %d format is meant for LONGS.  This
> is also true for %f.  I am not certain, but pretty sure that I have gotten
> wrong behavior when using %ld in this context on certain hardware.

If this were true, why was %ld provided?
I thought that chars and shorts got promoted to ints.
Ints and longs happen to be the same size on some systems, but in
general, ints get passed as ints.  Printf expects an int when it sees %d
and a long when it sees %ld.  If they're the same size, you can use them
interchangeably, unless you care about portability!
-- 
Dave Levenson
Westmark, Inc.		A node for news.
Warren, NJ USA
{rutgers | clyde | mtune | ihnp4}!westmark!dave

gwyn@brl-smoke.ARPA (Doug Gwyn ) (09/21/87)

In article <9266@brl-adm.ARPA> moss@BRL.ARPA (Gary S. Moss (SLCBR-VL-V)) writes:
>The reason for this is that integer arguments are *always* widened to LONG
>when passed in to a function, so the %d format is meant for LONGS.

This is completely wrong!  Pre-ANSI C function arguments are widened,
all right, but not to (long).  All non-long integral types are widened
to (int) (or (unsigned int), same size).  %ld should not be used with
(int) parameters to *printf(), but only with (long) parameters.

Scanf(), since it takes pointers, is unaffected by parameter widening.