Thread overview
Dernel: pointer arithmetic question
Mar 02, 2004
Robert M. Münch
Mar 02, 2004
Russ Lewis
Mar 04, 2004
Robert M. Münch
Mar 04, 2004
Ilya Minkov
March 02, 2004
Hi, I'm a bit confused how to do pointer arithmetic correctly. I have the following code:

struct memory_map {
	uint entry_size;
	uint base_addr_low;
	uint base_addr_high;
	uint length_low;
	uint length_high;
	uint type;
}

Than I have a loop:

for(memory_map *mem_map = (memory_map*)mbi.mmap_addr;
  (uint) mem_map <= (uint)(mbi.mmap_addr + mbi.mmap_length);
  mem_map = (mem_map + mem_map.entry_size + mem_map.entry_size.sizeof)) {

The last line is the problem: mem_map is set to something way off in memory. If I change the line to:

  mem_map = (memory_map*)((uint)mem_map + mem_map.entry_size + mem_map.entry_size.sizeof);

it works. So, why do I need to use explicit casts? What does D do, if I don't convert mem_map to uint but still add some stuff.

-- 
Robert M. Münch
Management & IT Freelancer
http://www.robertmuench.de
March 02, 2004
When you add something to a pointer, it increments the pointer by the size of the type.  So, for example:

	byte *foo = (byte*)0x1000;
	foo++;	// foo now equals 0x1001
	uint *bar = (uint*)0x1000;
	bar++;	// bar now equals 0x1004, since uint.size == 4
	MyStruct *baz = (MyStruct*)0x1000;
	baz++;	// baz now equals 0x1000+MyStruct.size

(Unless your pointer is a (byte*)) you should NEVER do this:
	ptr_variable + <somethingElse>.sizeof
since sizeof returns the size in bytes but when you add you are adding in terms of the size of the thing the pointer points to!

The reason your 2nd code worked is because you cast the pointer to a uint, did the arithmetic by hand, and then cast back to a pointer.



Ordinarily, when you have an array of structs, you can just use ordinary pointer arithmetic...just make sure that the things you add (or subtract) are the number of structs you want to increment, not the number of bytes.  But if you need to do byte arithmetic, my preferred way is to cast things to (byte*):

	MyStruct *foo;
	foo = (MyStruct*)(((byte*)base_pointer) + offset_in_bytes);

* So you first cast your pointer to a (byte*)
* Then you do pointer arithmetic...but since the size of 'byte' is 1, you are offsetting in terms of bytes
* Then you cast back to your desired pointer type.

(I think that) this should produce the exact same assembly language as if you cast the pointer to a (uint), but this is easier to read.

See also http://digitalmars.com/d/expression.html.  Read the section on "Add Expressions."

Russ

Robert M. Münch wrote:
> Hi, I'm a bit confused how to do pointer arithmetic correctly. I have the  following code:
> 
> struct memory_map {
>     uint entry_size;
>     uint base_addr_low;
>     uint base_addr_high;
>     uint length_low;
>     uint length_high;
>     uint type;
> }
> 
> Than I have a loop:
> 
> for(memory_map *mem_map = (memory_map*)mbi.mmap_addr;
>   (uint) mem_map <= (uint)(mbi.mmap_addr + mbi.mmap_length);
>   mem_map = (mem_map + mem_map.entry_size + mem_map.entry_size.sizeof)) {
> 
> The last line is the problem: mem_map is set to something way off in  memory. If I change the line to:
> 
>   mem_map = (memory_map*)((uint)mem_map + mem_map.entry_size  + mem_map.entry_size.sizeof);
> 
> it works. So, why do I need to use explicit casts? What does D do, if I  don't convert mem_map to uint but still add some stuff.
> 

March 04, 2004
On Tue, 02 Mar 2004 07:20:41 -0700, Russ Lewis <spamhole-2001-07-16@deming-os.org> wrote:

> When you add something to a pointer, it increments the pointer by the size of the type.  So, for example:
>
> 	byte *foo = (byte*)0x1000;
> 	foo++;	// foo now equals 0x1001
> 	uint *bar = (uint*)0x1000;
> 	bar++;	// bar now equals 0x1004, since uint.size == 4
> 	MyStruct *baz = (MyStruct*)0x1000;
> 	baz++;	// baz now equals 0x1000+MyStruct.size

Hi, ah I missed this. Is this true for C++ as well? Hmm... seems I never used such a feature.

> The reason your 2nd code worked is because you cast the pointer to a uint, did the arithmetic by hand, and then cast back to a pointer.

Of course now it makes sense.

> But if you need to do byte arithmetic, my preferred way is to cast things to (byte*):
>
> 	MyStruct *foo;
> 	foo = (MyStruct*)(((byte*)base_pointer) + offset_in_bytes);
>
> * So you first cast your pointer to a (byte*)
> * Then you do pointer arithmetic...but since the size of 'byte' is 1, you are offsetting in terms of bytes
> * Then you cast back to your desired pointer type.

Yes, good point. Thanks a lot. Robert
March 04, 2004
Robert M. Münch wrote:
> On Tue, 02 Mar 2004 07:20:41 -0700, Russ Lewis  <spamhole-2001-07-16@deming-os.org> wrote:
> 
>> When you add something to a pointer, it increments the pointer by the  size of the type.  So, for example:

> Hi, ah I missed this. Is this true for C++ as well? Hmm... seems I never  used such a feature.

Yes. "Pointer Arithmetic" is inherited from C.