www.digitalmars.com         C & C++   DMDScript  

D - Dernel: pointer arithmetic question

reply "=?iso-8859-1?Q?Robert_M._M=FCnch?=" <robert.muench robertmuench.de> writes:
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
Mar 02 2004
parent reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
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.
 
Mar 02 2004
parent reply "=?iso-8859-1?Q?Robert_M._M=FCnch?=" <robert.muench robertmuench.de> writes:
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
Mar 03 2004
parent Ilya Minkov <minkov cs.tum.edu> writes:
Robert M. M=FCnch wrote:
 On Tue, 02 Mar 2004 07:20:41 -0700, Russ Lewis =20
 <spamhole-2001-07-16 deming-os.org> wrote:
=20
 When you add something to a pointer, it increments the pointer by the =
=20
 size of the type.  So, for example:
 Hi, ah I missed this. Is this true for C++ as well? Hmm... seems I=20
 never  used such a feature.
Yes. "Pointer Arithmetic" is inherited from C.
Mar 04 2004