Aligning a pointer

BlitzMax Forums/BlitzMax Programming/Aligning a pointer

Brucey(Posted 2016) [#1]
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 :-)


Yasha(Posted 2016) [#2]
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.


Brucey(Posted 2016) [#3]
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 :-)


grable(Posted 2016) [#4]
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.


Henri(Posted 2016) [#5]
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


Floyd(Posted 2016) [#6]
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.


Floyd(Posted 2016) [#7]
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



Henri(Posted 2016) [#8]
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


Floyd(Posted 2016) [#9]
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.


GW(Posted 2016) [#10]
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?


Henri(Posted 2016) [#11]
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