Aligning a pointer
BlitzMax Forums/BlitzMax Programming/Aligning a pointer
| ||
Hello clever folks! I have a C struct, at the end of which is an array scales[1] of ints. The actual (real) size of this array is determined at runtime. At the end of *this* array I have some data of a runtime-determined size. I would like to always locate this data at a 16-byte aligned offset. struct BBArray{ BBClass* clas; const char* type; int dims; unsigned int size; int data_size; int scales[1]; }; // in memory data looks like this : [ allocated memory ] [ struct ][ scales*n -1][padding?][ data ] ^ 16-byte aligned offset to place data I'm sure there's some magic bit math one can apply to work out how much padding I need to always guarantee my data starts 16-byte aligned. Thanks in advance :-) |
| ||
If the alignment is a power of two (which it usually is), you can use:MASK = ALIGNMENT - 1 aligned_size = (size + MASK) & ~MASK If it's already aligned, this won't change the value. Otherwise, it'll bump it up to or past the alignment point and then mask off any undesired bits that would take it too far. Ref. |
| ||
Ah, okay. So I calculate "struct + scales * n - 1", add $f and then negate by $f and use the result as the offset for my data. Cool! Magic :-) |
| ||
If you are targeting C11 there is also aligned_alloc, which saves you from having to stash the real pointer (or enough bits to calculate the real address) somewhere. |
| ||
Just to make this thread longer here is what I used in Blitzmax:Function AlignW:Short Ptr(sp:Short Ptr) sp:+ 1 Local int_ptr:Int = Int(sp) Return Short Ptr( (int_ptr Shr 1) Shl 1) EndFunction -Henri |
| ||
Comments on this code:Function AlignW:Short Ptr(sp:Short Ptr) sp:+ 1 Local int_ptr:Int = Int(sp) Return Short Ptr( (int_ptr Shr 1) Shl 1) EndFunction That doesn't do what you think would expect. sp is a pointer to a Short, which is already 2-byte aligned. So sp is an even number. The least significant bit is 0. sp:+ 1 is pointer arithmetic. It does not add 1 to sp. It adds the size of Short, i.e. 2, to sp. Thus sp is still an even number. (int_ptr Shr 1) Shl 1 Changes nothing since the number was already even. Ultimately AlignW returns the address held by sp, increased by two. SuperStrict Local s:Short Local sptr:Short Ptr sptr = Varptr( s ) Print Print "Increment the value of a Short Ptr" Print Print Int( sptr ) sptr:+ 1 Print Int( sptr ) ' sptr has increased by TWO, the number of bytes in a Short. Pointer arithmetic is modelled after traditional use in C. The idea was that a block of memory would be used like an array. If p points to an element of array then incrementing or decrementing p moves through the array, pointing to the next element after or before the current one. The pointer can only change by a multiple of the size of the data type it points to. |
| ||
As long as I'm rambling on the topic of pointer arithmetic... The only valid operations are to add or subtract a number, as already explained, or to take the difference of two pointers to the same data type. Try uncommenting the last line to see that addition of pointers doesn't work. SuperStrict Local s:Short Local sptr:Short Ptr sptr = Varptr( s ) Local tptr:Short Ptr tptr = sptr + 5 Print Int(sptr) Print Int(tptr) Print tptr - sptr Print sptr - tptr ' This is illegal pointer arithmetic. Adding pointers doesn't make sense. ' Print sptr + tptr |
| ||
Hi Floyd, does this make more sense: Function AlignDW:Short Ptr(sp:Short Ptr) sp:+ 3 Local int_ptr:Int = Int(sp) Return Short Ptr( (int_ptr Shr 2) Shl 2) EndFunction As it turns out I have not used the earlier posted function anywhere. I'm assuming this function would align to 32-bit boundary ? It is something that I used in Windows API dialogs and it seemed to do the job. -Henri |
| ||
If I'm visualizing this correctly that would increase sp by four or six bytes to a multiple of four. The idea is that (int_ptr Shr 2) Shl 2 sets the last two bits to 0. So it is a multiple of four, rounding down if needed. sp:+ 3 actually adds six. So considering everything Mod 8 ( just the last three bits ) AlignDW does 0 becomes 6 and then rounds down to 4. 2 becomes 8 and then stays at 8, already a multiple of 4. |
| ||
Gcc has the __attribute__((aligned(16))) vcpp does it automatically. Gcc is probably doing it automatically too. have you encountered malloced data that is not? |
| ||
Hi GW, not sure if this was directed at me, but in my case I was storing Windows resources in memory which were allocated runtime and needed to be allocated in one continues junk of memory with each resource starting 32-bit aligned, or otherwise the Windows API - function would crash. -Henri |