[comp.lang.c] Pointer and integer addition

dzoey@terminus.umd.edu (Joe Herman) (03/29/91)

Hello, I have a section of code that scans through a block of variable
length records.  The structure looks more or less like this:

struct foo {
	unsigned short recsize;
	unsigned short num;
	char info [24];
	byte flags;
	char filename[1]
};

Where, foo.filename is a placeholder for a variable length string.

After I process one record, I'd like to just increment the pointer to
point to the next record.  What I'd like to do is:

fooptr += fooptr->recsize;

However, the compiler I'm using increments the pointer by
recsize * sizeof (struct foo).   This is probably correct.

Next, I tried

fooptr = (char *) fooptr + fooptr->recsize;

No difference, so I guess it gets the value to multiply the increment from
the lvalue.

Is there a way to do what I want without using a temporary variable
(such as assigning to a char * and then doing the increment) or
converting the pointer to an integral type, doing the addition and
converting back?

				Thanks,
				Joe Herman

dzoey@terminus.umd.edu



-- 
"Everything is wonderful until you know something about it."

willcr@bud.sos.ivy.isc.com (Will Crowder) (03/30/91)

In article <8334@umd5.umd.edu>, dzoey@terminus.umd.edu (Joe Herman) writes:
|> Hello, I have a section of code that scans through a block of variable
|> length records.  The structure looks more or less like this:
|> 
|> struct foo {
|> 	unsigned short recsize;
|> 	unsigned short num;
|> 	char info [24];
|> 	byte flags;
|> 	char filename[1]
|> };
|> 
|> Where, foo.filename is a placeholder for a variable length string.
|> 
|> After I process one record, I'd like to just increment the pointer to
|> point to the next record.  What I'd like to do is:
|> 
|> fooptr += fooptr->recsize;
|> 
|> However, the compiler I'm using increments the pointer by
|> recsize * sizeof (struct foo).   This is probably correct.

Indeed, that is the correct behavior.

|> Next, I tried
|> 
|> fooptr = (char *) fooptr + fooptr->recsize;
|>
|> No difference, so I guess it gets the value to multiply the increment from
|> the lvalue.

I'm surprised that there was no difference here.  The cast of fooptr to
(char *) in the expression should have behaved as you expected.  Both Sun CC
and gcc do what you want here, although both issue a warning about assignments
between incompatible pointer types.  To quiet the warning and make it clear
what you are doing:

	fooptr = (struct foo *)((char *)fooptr + fooptr->recsize);

However, there are other potential pitfalls here having to do with data
alignment restrictions.  If struct foo needs to be aligned on a particular
boundary, then you can get into trouble adding non (sizeof struct foo)-sized
chunks to the pointer.  (The addition will succeed, or should, but you may
get an alignment exception on your next access via fooptr.)

|> 				Thanks,
|> 				Joe Herman
|> 

You're welcome.  Hope this helps.  OBTW, your compiler may be broken.  Which
one is it?

Will

--------------------------------------------------------------------------------
Will Crowder, MTS            | "That was setting #1.  Anyone want to see
(willcr@ivy.isc.com)         |  setting #2?"
INTERACTIVE Systems Corp.    |		-- Guinan

lamont@uts.amdahl.com (Duane Richard LaMont) (03/30/91)

In article <8334@umd5.umd.edu> dzoey@terminus.umd.edu (Joe Herman) writes:
>Next, I tried
>
>fooptr = (char *) fooptr + fooptr->recsize;
>
>No difference, so I guess it gets the value to multiply the increment from
>the lvalue.

You were definitely on the right track, try:

    (char *) fooptr += fooptr->recsize;


Rick LaMont

gwyn@smoke.brl.mil (Doug Gwyn) (03/30/91)

In article <8334@umd5.umd.edu> dzoey@terminus.umd.edu (Joe Herman) writes:
>fooptr = (char *) fooptr + fooptr->recsize;

This (almost) should have worked.  You also need to convert back to
the proper pointer type before the assignment:

	fooptr = (struct foo *) ((char *) fooptr + fooptr->recsize);

id8rld06@serss0.fiu.edu (Michael N Johnston) (03/31/91)

>struct foo {
>unsigned short recsize;
>unsigned short num;
>char info [24];
>byte flags;
>char filename[1]
>};
>Where, foo.filename is a placeholder for a variable length string.

>After I process one record, I'd like to just increment the pointer to
>point to the next record.  What I'd like to do is:
>fooptr += fooptr->recsize;

>However, the compiler I'm using increments the pointer by
>recsize * sizeof (struct foo).   This is probably correct.

If you are declaring foo_ptr as
struct foo *foo_ptr;

then this is indeed correct operation. What you need to do to incrment
foo_ptr to point to the next record is (assuming foo_ptr is pointing
to an array of struct foo):
++foo_ptr;

If you plan to store a char array in filename DON'T. Use char *filename
and point this to your actual array. Using your origional declaration
and doing something like strcpy(foo_ptr->filename, "abcde") will lead
to disaster.

Good Luck,
Mike
--
====================================================================

Michael Johnston
id8rld06@serss0.fiu.edu or

berg@marvin.e17.physik.tu-muenchen.de (Stephen R. van den Berg) (04/11/91)

In article <15631@smoke.brl.mil> gwyn@smoke.brl.mil (Doug Gwyn) writes:
>In article <8334@umd5.umd.edu> dzoey@terminus.umd.edu (Joe Herman) writes:
>>fooptr = (char *) fooptr + fooptr->recsize;

>This (almost) should have worked.  You also need to convert back to
>the proper pointer type before the assignment:

>	fooptr = (struct foo *) ((char *) fooptr + fooptr->recsize);

No, not needed, the cast is implicit.
--
Sincerely,                 berg@marvin.e17.physik.tu-muenchen.de
           Stephen R. van den Berg.
"I code it in 5 min, optimize it in 90 min, because it's so well optimized:
it runs in only 5 min.  Actually, most of the time I optimize programs."

berg@marvin.e17.physik.tu-muenchen.de (Stephen R. van den Berg) (04/11/91)

Duane Richard LaMont writes:
>You were definitely on the right track, try:

>    (char *) fooptr += fooptr->recsize;

THAT, is not allowed.  (See discussion about "increment casted void-pointer").
--
Sincerely,                 berg@marvin.e17.physik.tu-muenchen.de
           Stephen R. van den Berg.
"I code it in 5 min, optimize it in 90 min, because it's so well optimized:
it runs in only 5 min.  Actually, most of the time I optimize programs."

willcr@bud.sos.ivy.isc.com (Will Crowder) (04/12/91)

In article <4205@rwthinf.UUCP>, berg@marvin.e17.physik.tu-muenchen.de
(Stephen R. van den Berg) writes:

|> In article <15631@smoke.brl.mil> gwyn@smoke.brl.mil (Doug Gwyn) writes:
|> >In article <8334@umd5.umd.edu> dzoey@terminus.umd.edu (Joe Herman) writes:
|> >>fooptr = (char *) fooptr + fooptr->recsize;
|> 
|> >This (almost) should have worked.  You also need to convert back to
|> >the proper pointer type before the assignment:
|> 
|> >	fooptr = (struct foo *) ((char *) fooptr + fooptr->recsize);
|> 
|> No, not needed, the cast is implicit.

But will result in a compiler warning on most compilers.  It also makes it
quite clear what is going on.  You cannot blithely assign one pointer type
to another without expecting some kind of complaint from the compiler.

|> --
|>            Stephen R. van den Berg.

--------------------------------------------------------------------------------
Will Crowder, MTS            | "I was gratified to be able to answer promptly,
(willcr@ivy.isc.com)         |  and I did: I said I didn't know."
INTERACTIVE Systems Corp.    |		-- Mark Twain

gwyn@smoke.brl.mil (Doug Gwyn) (04/13/91)

In article <4205@rwthinf.UUCP> berg@marvin.e17.physik.tu-muenchen.de (Stephen R. van den Berg) writes:
>No, not needed, the cast is implicit.

No, without the cast you have violated a constraint in the C standard
(section 3.3.16.1 in ANS X3.159-1989) and a standard-conforming
implementation is obliged to produce a diagnostic.