• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 2048
  • Last Modified:

BYTE, WORD, DWORD alignment when allocating memory

Hi,

(FYI : using Borland cpp Builder 4.x)

I came accross a situation where (sometimes) I need to make sure the allocated memory is aligned.
(otherwise function from dll refuses/rejects)

e.g. check :
BYTE Buffer[1000] ;
if ((Buffer & 0x0001) == 0x00) { // WORD alligned }
if ((Buffer & 0x0003) == 0x00) { // DWORD alligned }

Ok, I can check (see above) but how can I make sure the memory that I allocate is aligned in a certain manner ?
Same for dynamically allocating memory ??
BYTE *DynamBuffer = new BYTE[10000] ;

Are there methods and tips ??

I started programming very recently, bought a book c++ in 21 days and here I am.  So, immediately started from the concept 'all' can be done with the operator 'new'.
Maybe commands like malloc etc.. prove more usefull ?????
Never used them ... enlighten me.

Thanks,
sneeuw
0
sneeuw
Asked:
sneeuw
  • 4
  • 2
1 Solution
 
nietodCommented:
First of all, VC guarantees that the memory returned by will begin in a paragraph boundary (its address is a multiple of 16).  So new always returns memory that is DWORD alligned (even "more" alligned than that).  I suspect that BC and BCB will also make this guarantee, but I don't know for sure.

However, even without the guarantee, you can make it work, details follow.
0
 
nietodCommented:
The trick is to request a little "extra" space in the allocation so that the data can be placed in the allocated block at a position where it will be properly aligned no matter what address the block starts at (i.e. the data might be placed in the block at a position that is not the start of a block.)

Consider a case where you want to align a DWORD value to a DWORD address (address that is evenly divisble by 2).  For this you would allocate 3 bytes.  if the block is allocated on a DWORD address, you then place the data at the start of the block.  If the block is allocated at an odd address (DWORD address+1), then the 2nd byte of the block will be at an even (DWORD) address, so you place the data in the 2nd (and 3rd) byte of the block and ignore the 1st byte.

continues
0
 
nietodCommented:
Now in general, I you need to place data at a address that is evenly divisible by X you need to allocate X-1 bytes of extra space.  So if you need to allocate something at a paragraph address (evenly divisible by 16), you must allocate 15 bytes of extra space.

Once you've alocated the extra space, you need to figure out how many bytes initially to skip.  Mathematically there are a few ways to do this, some can take advantage of the fact that the allignment is a power of 2, although would fail if it weren't a power of 2.  What I would suggest is to use a formula of

Offset = Alignment - (Address mod Allignment)

where Allignment is the value you want to allign to, like 2 if you need to allign to a WORD address and 4 if you need to allgn to a DWORD address etc.  Address is the address of the allocated block.

This will work best if you are dealing with POD (plain old data), that is data that does not have constructors/destructor/virtual functions etc.  i.e raw data.  For this sort of data you can use new to allocate a specific number of bytes and adjust that number to allow room for your extra padding.  If necessary you can convert that pointer returned by new to a different type for use when you need to store the data.  For example the following will allocate memory for storing a WORD.  It does this by allocaiting three bytes (characters) and the generating an alligned WORD pointer into the block.

char *BlockPtr = char[3];
size_t Address = BlockPtr - 0; // Convert to an address.
size_t Offset = 2 - (Address % 2);
WORD *WrdPtr = (WORD *) (Address + Offset);

continues
0
Never miss a deadline with monday.com

The revolutionary project management tool is here!   Plan visually with a single glance and make sure your projects get done.

 
nietodCommented:
Now if you need to do this with data that is not POD, that is data that must be initialized (has a constructor or virtual functions etc.) then this won't work.   There are 2 approaches to make this work.  You can allocate the raw data as i suggested above then use placement new to initialize the data.  This would work well if you only need to have the allocated data aligned in one specific place.  i.e. only one place in your program requires this.  If the data is allcoated in lots of placed and needs to be a alligned in all of them, then you might want to overload operator new and operator delete for the class.  The overloaded operators would have to go through the process suggested above to make the data aligned.  However there is a wrinkle that makes it hard to do.  operator delete would not be provided with a pointer to the originally allocated block, it would have a pointer to the alligned data within the block.  (This is a common problem).  The standard solution in this case is to allcoate even more extra space.  This space is used to store a pointer to the start of the allocated block.  This pointer is stored in the bytes immediately before the alligned data.  I can provide more details if needed, but this can be a little complex.

Let me know if you have any questions.
0
 
sneeuwAuthor Commented:
I'll try it out tomorrow evening !!!!

Thanks Nietod,
Sharp as ever !
0
 
sneeuwAuthor Commented:
Hi Nietod,

Haven't been able to check.
But I trust you were complete.

Read it and seems doable anyway !
Thanks,
Sneeuw
0

Featured Post

Never miss a deadline with monday.com

The revolutionary project management tool is here!   Plan visually with a single glance and make sure your projects get done.

  • 4
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now