[comp.lang.c] Beginning C question.

wsze@nunki.usc.edu (Wally "The Whale" Sze) (07/24/90)

I have a (beginning C) problem with a program I am working on. My
compiler uses 16-bit ints, and I need to read some 32bit long ints
from disk. 

(as a background, I wrote the same program for unix, and it worked
fine when I used getw(), but on my home compiler it doesn't.. getw()
returns only 16 bits).

A way I can see to solve this is to read two ints from disk and
concantenate them. But how do you concantenate ints? Say I have
a = 0x20df and b = 0x3244, and want to get a long int 0x20df3244.
If anyone can help, or if you can think of a better way to do this,
please let me know by mail. Thank you.

jrh@mustang.dell.com (James Howard) (07/24/90)

In article <10997@chaph.usc.edu>, wsze@nunki.usc.edu (Wally "The Whale"
Sze) writes:
> I have a (beginning C) problem with a program I am working on. My
> compiler uses 16-bit ints, and I need to read some 32bit long ints
> from disk. 
> 
> (as a background, I wrote the same program for unix, and it worked
> fine when I used getw(), but on my home compiler it doesn't.. getw()
> returns only 16 bits).
> 
> A way I can see to solve this is to read two ints from disk and
> concantenate them. But how do you concantenate ints? Say I have
> a = 0x20df and b = 0x3244, and want to get a long int 0x20df3244.
> If anyone can help, or if you can think of a better way to do this,
> please let me know by mail. Thank you.

This works on my system:

main()
{
        short a=0x20df;
        short b=0x3244;
        int   c;

c = (a<<16) + b;
printf("c = %x\n",c);

exit(0);
}

I used "short" because they're 16 bits on this machine, and int's are 32.


James Howard        Dell Computer Corp.        !'s:uunet!dell!mustang!jrh
(512) 343-3480      9505 Arboretum Blvd        @'s:jrh@mustang.dell.com
                    Austin, TX 78759-7299   

gdtltr@freezer.it.udel.edu (Gary Duzan) (07/24/90)

In article <7703@uudell.dell.com> jrh@mustang.dell.com (James Howard) writes:
=>In article <10997@chaph.usc.edu>, wsze@nunki.usc.edu (Wally "The Whale"
=>Sze) writes:
=>> 
=>> A way I can see to solve this is to read two ints from disk and
=>> concantenate them. But how do you concantenate ints? Say I have
=>> a = 0x20df and b = 0x3244, and want to get a long int 0x20df3244.
=>> If anyone can help, or if you can think of a better way to do this,
=>> please let me know by mail. Thank you.
=>
=>This works on my system:
=>
=>main()
=>{
=>        short a=0x20df;
=>        short b=0x3244;
=>        int   c;
=>
=>c = (a<<16) + b;
=>printf("c = %x\n",c);
=>
=>exit(0);
=>}
=>
=>I used "short" because they're 16 bits on this machine, and int's are 32.
=>
   Doesn't this depend on the implementation of putw and endianness? Since
putw isn't standard (correct me if I'm wrong; it isn't in K&RII) it is 
difficult to say. I can easily see a case where c=a+(b<<16) might be right,
or where you might have to deal with each byte. I doubt if this could be
written portably. Of course, if portability isn't a concern, try Wally's
solution and see if it works.

                                        Gary Duzan
                                        Time  Lord
                                    Third Regeneration



--
                          gdtltr@freezer.it.udel.edu
   _o_                    --------------------------                      _o_
 [|o o|] If you can square, round, or cube a number, why not sphere it? [|o o|]
  |_O_|         "Don't listen to me; I never do." -- Doctor Who          |_O_|

arensb@cvl.umd.edu (Andrew Arensburger) (07/25/90)

In article <25440@nigel.udel.EDU> gdtltr@freezer.it.udel.edu (Gary Duzan) writes:
>In article <7703@uudell.dell.com> jrh@mustang.dell.com (James Howard) writes:
>=>main()
>=>{
>=>        short a=0x20df;
>=>        short b=0x3244;
>=>        int   c;
>=>
>=>c = (a<<16) + b;
>=>
>=>I used "short" because they're 16 bits on this machine, and int's are 32.
>=>
>   Doesn't this depend on the implementation of putw and endianness?

	Only if you're reading from a file, or if you originally got
'a' and 'b' by reading individual bytes from memory.
	James's example works correctly because the following assumptions
are true:
	1) The bits in 'a' are arranged in the order in which they
should appear in 'c'.
	2) The bits in 'b' are arranged in the order in which they
should appear in 'c'.
	3) Each bit in 'a' is more significant than any bit in 'b'.
	4) 'b' is 16 bits long.

	Thus, GIVEN that 'a' is the correct most significant half of 'c',
and GIVEN that 'b' is the correct least significant half of 'c', THEN
the statement 'c = (a << 16) + b;' is correct.
	If any of the givens are false, then the result is also false.
And yes, you're right: the givens depend on byte order for longs and
shorts.
	My apologies to anyone who's more confused now than before the
question was raised.

-- 
-------------------------------------------------------------------\\\\^
Andrew Arensburger            | K&R C!   |  "Avoid the (void)"         o\\\\\-
...!uunet!mimsy!cvl!arensb    | ANSI no! |       -- Domino's       __   /
arensb@cvl.umd.edu            |          |          C compiler       \_/

coy@ssc-vax.UUCP (Stephen B Coy) (07/26/90)

In article <7703@uudell.dell.com>, jrh@mustang.dell.com (James Howard) writes:
> main()
> {
>         short a=0x20df;
>         short b=0x3244;
>         int   c;
> 
> c = (a<<16) + b;
> printf("c = %x\n",c);
> 
> exit(0);
> }
> 
> I used "short" because they're 16 bits on this machine, and int's are 32.

On a 16 bit int system c must be a long and a must be cast to long
in the equation otherwise the bits will be shifted off into a black
hole.

> James Howard        Dell Computer Corp.        !'s:uunet!dell!mustang!jrh
> (512) 343-3480      9505 Arboretum Blvd        @'s:jrh@mustang.dell.com
>                     Austin, TX 78759-7299   

Stephen Coy
uw-beaver!ssc-vax!coy

evil@arcturus.uucp (Wade Guthrie) (07/26/90)

Wally Sze writes:
> [...] My
> compiler uses 16-bit ints, and I need to read some 32bit long ints
> from disk. 

Try fread().  For example:

	#include <stdio.h>

	...

	FILE	*file, *fopen();
	long	foo;
	int	items = 1, actual_num;

	...

	if( (file = fopen(...)) == NULL)
		/* some error handling here */
	if((actual_num = fread(&foo, sizeof(foo), items, file)) != items)
		fprintf(stderr, "fread only read %d items", actual_num);

In the scope of a prototype of fread (to allow for the proper cast
of &foo) will read a single long into foo.
-- 
Wade Guthrie (evil@arcturus.UUCP)    | "He gasped in terror at what sounded
Rockwell International; Anaheim, CA  | like a man trying to gargle while
My opinions, not my employer's.      | fighting off a pack of wolves"
                                     |                Hitchhiker's Guide

ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) (07/26/90)

In article <4561@cvl.umd.edu>, arensb@cvl.umd.edu (Andrew Arensburger) writes:
> In article <25440@nigel.udel.EDU> gdtltr@freezer.it.udel.edu (Gary Duzan) writes:
> >In article <7703@uudell.dell.com> jrh@mustang.dell.com (James Howard) writes:
> >=>        short a=0x20df;
> >=>        short b=0x3244;
> >=>        int   c;
> >=>
> >=>	c = (a<<16) + b;
> >=>
> >=>I used "short" because they're 16 bits on this machine, and ints are 32.

> 	James's example works correctly because the following assumptions
> are true:

Bad news, friends, the example DOESN'T work correctly, even if the
half-word sex of the machine is right.  Suppose the high bit of b is 1.
That's the _sign_ bit, remember.  The effect in that case is as if 1
were subtracted from a.  (I tried it, and that _does_ happen.)

Instead, use
	c = (a << 16) | (b & 0xFFFF);
or make a and b "unsigned short" and do
	c = (int)((a << 16) + b);

-- 
Science is all about asking the right questions.  | ok@goanna.cs.rmit.oz.au
I'm afraid you just asked one of the wrong ones.  | (quote from Playfair)