Annoyances with pointer offsets.

Started by
16 comments, last by iMalc 18 years, 9 months ago
You mean...

struct mysurfacestruct
{
int a;
int b;
struct RGB *colors;
}

And than....

mySurface.colors = malloc(width*height);

Since otherwise it would be a struct with indefinent elements.
Advertisement
right. I forgot about it holding an arbitrary number of RGB elements.
Quote:(&array[1] + 1) is EXACTLY equivalent to (&array[2])


That's because foo really means *(foo + i).

Quote:I'm fine with this if its bytes (Since +1 byte <=> the next byte), but when working with structures (Or any variable greater than 1 byte in size), I disagree with the standards.


I don't. It's perfectly rational. Get over it. Pointer arithmetic is intended to iterate over arrays - as such the step must be the size of the array element. If you want to apply a different offset, cast to char*.


template<class T>T* byte_offset(T* ptr, long offset){   return (T*)(offset + (char*)ptr);}
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
char *byte = (char*) &intary[5];char b0 = byte[0]char b1 = byte[1]char b2 = byte[2]char b3 = byte[3]

Think of it this way. int *p = foo();

p now points to an int. You can dereference p and do any sort of int related thing you want. If p+1 pointed to the next byte rather than the next element what would p point to? It would point to garbage. Dereferencing p may very well crash your app (because of alignment or other hardware design issues). The fact that in this particular case ((int *)((byte *)p)+1) might point to something useful is an accident caused by circumventing the type system.

Besides, the vast majority of time people work with elements and having to go p+sizeof(*p) all the time would be annoying and very error-prone.
-Mike
Keep in mind that on some systems, unaligned memory accesses aren't possible:

int foo;*static_cast<int*>(static_cast<char*>(&foo) + 1); // Boom// I think this happens to be ok on x86 architecture, but will blow up on// almost everything Motorola ever made :/
x[y] is *(x+y) is *(y+x) is y[x], now and for ever.

As a result you can write something silly like cout << 4["Hello"] to print 'o'.

Even if it did do what you wanted in your example, you still end up with an integer when you dereference it, not the byte you wanted. You'd need to cast it regardless. The current method is better because you can skip multiplying by it's size, which you would need to do in every other case.
Chess is played by three people. Two people play the game; the third provides moral support for the pawns. The object of the game is to kill your opponent by flinging captured pieces at his head. Since the only piece that can be killed is a pawn, the two armies agree to meet in a pawn-infested area (or even a pawn shop) and kill as many pawns as possible in the crossfire. If the game goes on for an hour, one player may legally attempt to gouge out the other player's eyes with his King.
The better way I spoke of would be:
struct RGB {  unsigned char r, g, b;};struct MySurface {  int width, height;  RGB colorData[0]; //May have to use a 1 here if your compiler wont allow zero length arrays.};
Of course, you'd allocate a MySurface with (width*height*3)+8 bytes.
It's laid out exactly the same in memory and you can access everything sensibly.

Do you now see how you were basically using a high-level-language as if it were a low-level-language (like asm). Make sure that your data structure matches the actual data. You were making things hard for yourself by not doing so.

Compiler pointer arithmetic addressing behaviour IS CORRECT, there is no question about that.
"In order to understand recursion, you must first understand recursion."
My website dedicated to sorting algorithms

This topic is closed to new replies.

Advertisement