I'm trying to allocate an array of struct and I want each struct to be aligned to 64 bytes.
I tried this (it's for Windows only for now), but it doesn't work (I tried with VS2012 and VS2013):
struct __declspec(align(64)) A
{
std::vector<int> v;
A()
{
assert(sizeof(A) == 64);
assert((size_t)this % 64 == 0);
}
void* operator new[] (size_t size)
{
void* ptr = _aligned_malloc(size, 64);
assert((size_t)ptr % 64 == 0);
return ptr;
}
void operator delete[] (void* p)
{
_aligned_free(p);
}
};
int main(int argc, char* argv[])
{
A* arr = new A[200];
return 0;
}
The assert ((size_t)this % 64 == 0) breaks (the modulo returns 16). It looks like it works if the struct only contains simple types though, but breaks when it contains an std container (or some other std classes).
Am I doing something wrong? Is there a way of doing this properly? (Preferably c++03 compatible, but any solution that works in VS2012 is fine).
Edit:
As hinted by Shokwav, this works:
A* arr = (A*)new std::aligned_storage<sizeof(A), 64>::type[200];
// this works too actually:
//A* arr = (A*)_aligned_malloc(sizeof(A) * 200, 64);
for (int i=0; i<200; ++i)
new (&arr[i]) A();
So it looks like it's related to the use of new[]... I'm very curious if anybody has an explanation.
I wonder why you need such a huge alignment requirement, moreover to store a dynamic heap allocated object in the struct. But you can do this:
struct __declspec(align(64)) A
{
unsigned char ___padding[64 - sizeof(std::vector<int>)];
std::vector<int> v;
void* operator new[] (size_t size)
{
// Make sure the buffer will fit even in the worst case
unsigned char* ptr = (unsigned char*)malloc(size + 63);
// Find out the next aligned position in the buffer
unsigned char* endptr = (unsigned char*)(((intptr_t)ptr + 63) & ~63ULL);
// Also store the misalignment in the first padding of the structure
unsigned char misalign = (unsigned char)(endptr - ptr);
*endptr = misalign;
return endptr;
}
void operator delete[] (void* p)
{
unsigned char * ptr = (unsigned char*)p;
// It's required to call back with the original pointer, so subtract the misalignment offset
ptr -= *ptr;
free(ptr);
}
};
int main()
{
A * a = new A[2];
printf("%p - %p = %d\n", &a[1], &a[0], int((char*)&a[1] - (char*)&a[0]));
return 0;
}
I did not have your align_malloc and free function, so the implementation I'm providing is doing this:
It allocates larger to make sure it will fit in 64-bytes boundaries
It computes the offset from the allocation to the closest 64-bytes boundary
It stores the "offset" in the padding of the first structure (else I would have required a larger allocation space each time)
This is used to compute back the original pointer to the free()
Outputs:
0x7fff57b1ca40 - 0x7fff57b1ca00 = 64
Warning: If there is no padding in your structure, then the scheme above will corrupt data, since I'll be storing the misalignement offset in a place that'll be overwritten by the constructor of the internal members.
Remember that when you do "new X[n]", "n" has to be stored "somewhere" so when calling delete[], "n" calls to the destructors will be done. Usually, it's stored before the returned memory buffer (new will likely allocate the required size + 4 for storing the number of elements). The scheme here avoid this.
Another warning: Because C++ calls this operator with some additional padding included in the size for storing the array's number of elements, you'll might still get a "shift" in the returned pointer address for your objects. You might need to account for it. This is what the std::align does, it takes the extra space, compute the alignment like I did and return the aligned pointer. However, you can not get both done in the new[] overload, because of the "count storage" shift that happens after returning from new(). However, you can figure out the "count storage" space once by a single allocation, and adjust the offset accordingly in the new[] implementation.
Related
void Manager::byteArrayToDoubleArray(byte ch[]) {
int counter = 0;
// temp array to break the byte array into size of 8 and read it
byte temp[64];
// double result values
double res[8];
int index = 0;
int size = (sizeof(ch) / sizeof(*ch));
for (int i = 0; i < size; i++) {
counter++;
temp[i] = ch[i];
if (counter % 8 == 0) {
res[index] = *reinterpret_cast<double * const>(temp);
index++;
counter = 0;
}
}
}
Here result would be a list of double values with count = 8.
Your problem is two things. You have some typos and misunderstanding. And the C++ standard is somewhat broken in this area.
I'll try to fix both.
First, a helper function called laundry_pods. It takes raw memory and "launders" it into an array of a type of your choice, so long as you pick a pod type:
template<class T, std::size_t N>
T* laundry_pods( void* ptr ) {
static_assert( std::is_pod<std::remove_cv_t<T>>{} );
char optimized_away[sizeof(T)*N];
std::memcpy( optimized_away, ptr , sizeof(T)*N );
T* r = ::new( ptr ) T[N];
assert( r == ptr );
std::memcpy( r, optimized_away, sizeof(T)*N );
return r;
}
now simply do
void Manager::byteArrayToDoubleArray(byte ch[]) {
double* pdouble = laundry_pods<double, 8>(ch);
}
and pdouble is a pointer to memory of ch interpreted as an array of 8 doubles. (It is not a copy of it, it interprets those bytes in-place).
While laundry_pods appears to copy the bytes around, both g++ and clang optimize it down into a binary noop. The seeming copying of bytes around is a way to get around aliasing restrictions and object lifetime rules in the C++ standard.
It relies on arrays of pod not having extra bookkeeping overhead (which C++ implementations are free to do; none do that I know of. That is what the non-static assert double-checks), but it returns a pointer to a real honest to goodness array of double. If you want to avoid that assumption, you could instead create each doulbe as a separate object. However, then they aren't an array, and pointer arithmetic over non-arrays is fraught as far as the standard is concerned.
The use of the term "launder" has to do with getting around aliasing and object lifetime requirements. The function does nothing at runtime, but in the C++ abstract machine it takes the memory and converts it into binary identical memory that is now a bunch of doubles.
The trick of doing this kind of "conversion" is to always cast the double* to a char* (or unsigned char or std::byte). Never the other way round.
You should be able to do something like this:
void byteArrayToDoubleArray(byte* in, std::size_t n, double* out)
{
for(auto out_bytes = (byte*) out; n--;)
*out_bytes++ = *in++;
}
// ...
byte ch[64];
// .. fill ch with double data somehow
double res[8];
byteArrayToDoubleArray(ch, 64, res);
Assuming that type byte is an alias of char or unsigned char or std::byte.
I am not completly sure what you are trying to achieve here because of the code (sizeof(ch) / sizeof(*ch)) which does not make sense for an array of undefined size.
If you have a byte-Array (POD data type; something like a typedef char byte;) then this most simple solution would be a reinterpret_cast:
double *result = reinterpret_cast<double*>(ch);
This allows you to use result[0]..result[7] as long as ch[] is valid and contains at least 64 bytes. Be aware that this construct does not generate code. It tells the compiler that result[0] corresponds to ch[0..7] and so on. An access to result[] will result in an access to ch[].
But you have to know the number of elements in ch[] to calculate the number of valid double elements in result.
If you need a copy (because - for example - the ch[] is a temporary array) you could use
std::vector<double> result(reinterpret_cast<double*>(ch), reinterpret_cast<double*>(ch) + itemsInCh * sizeof(*ch) / sizeof(double));
So if ch[] is an array with 64 items and a byte is really an 8-bit value, then
std::vector<double> result(reinterpret_cast<double*>(ch), reinterpet_cast<double*>(ch) + 8);
will provide a std::vector containing 8 double values.
There is another possible method using a union:
union ByteToDouble
{
byte b[64];
double d[8];
} byteToDouble;
the 8 double values will occupie the same memory as the 64 byte values. So you can write the byte values to byteToDouble.b[] and read the resultingdouble values from byteToDouble.d[].
Not sure if "header" is the correct term, so please correct me if it isn't.
I'm trying to first allocate a memory, and then use an overloaded (placement) new[] operator to initialize an array of class objects (say, MyClass).
Say, the size of a MyClass object is 0x68, and I want an array of 0x20. So the total size is sizeof(MyClass) * 0x20 = 0xD00, or so I thought.
Now when I use my overloaded placement new[] operator :
pArr = new(pAllocatedMem)MyClass[0x20];
The compiler returned size_t to the new[] operator is actually 0xD08. There is an extra 8 bytes. Looking at the value of that 8 bytes, it's used to store the size of the array (0x20 in this case).
So is there a constant definition of what this header size is, say from WDK, that I can use? Does this size changes depends on compilers or what else?
That amount of that extra space, if any, is compiler dependent. For the languange definition [expr.new, paragraph 15]:
[It] is a non-negative unspecified value representing array allocation overhead; the result of the new-expression will be offset by this amount from the value returned by operator new[].
It is typically used by the runtime to know how many objects to destroy when delete is eventually called on the array.
Adding to the answer myself.
Did a little test with a colleague. It appears if the class to be initialized has a defined destructor function, the VS compiler will need that overhead storing the array size. No destructor, no overhead. Is that a bug or a feature?!.
#include <malloc.h>
#include <new>
class Foo
{
public:
//Foo() {}
//~Foo() {} // <-- will cause overhead even with user-allocated memory passed to placement new()
int a;
};
int main()
{
int n = 0x10;
size_t size = sizeof(int) * 2 + sizeof(Foo) * n;
void* p = malloc(size);
*((int*)p) = 0xaaaaaaaa;
*(int*)((char*)p + size - sizeof(int)) = 0xbbbbbbbb;
// Placement new with user-allocated memory
Foo* pf = new ((char*)p + sizeof(int)) Foo[n];
for (int i = 0; i < n; i++)
{
pf[i].a = i;
}
free(p);
return 0;
}
If I have a typedef of a struct
typedef struct
{
char SmType;
char SRes;
float SParm;
float EParm;
WORD Count;
char Flags;
char unused;
GPOINT2 Nodes[];
} GPATH2;
and it contains an uninitialized array, how can I create an instance of this type so that is will hold, say, 4 values in Nodes[]?
Edit: This belongs to an API for a program written in Assembler. I guess as long as the underlying data in memory is the same, an answer changing the struct definition would work, but not if the underlying memory is different. The Assembly Language application is not using this definition .... but .... a C program using it can create GPATH2 elements that the Assembly Language application can "read".
Can I ever resize Nodes[] once I have created an instance of GPATH2?
Note: I would have placed this with a straight C tag, but there is only a C++ tag.
You could use a bastard mix of C and C++ if you really want to:
#include <new>
#include <cstdlib>
#include "definition_of_GPATH2.h"
using namespace std;
int main(void)
{
int i;
/* Allocate raw memory buffer */
void * raw_buffer = calloc(1, sizeof(GPATH2) + 4 * sizeof(GPOINT2));
/* Initialize struct with placement-new */
GPATH2 * path = new (raw_buffer) GPATH2;
path->Count = 4;
for ( i = 0 ; i < 4 ; i++ )
{
path->Nodes[i].x = rand();
path->Nodes[i].y = rand();
}
/* Resize raw buffer */
raw_buffer = realloc(raw_buffer, sizeof(GPATH2) + 8 * sizeof(GPOINT2));
/* 'path' still points to the old buffer that might have been free'd
* by realloc, so it has to be re-initialized
* realloc copies old memory contents, so I am not certain this would
* work with a proper object that actaully does something in the
* constructor
*/
path = new (raw_buffer) GPATH2;
/* now we can write more elements of array */
path->Count = 5;
path->Nodes[4].x = rand();
path->Nodes[4].y = rand();
/* Because this is allocated with malloc/realloc, free it with free
* rather than delete.
* If 'path' was a proper object rather than a struct, you should
* call the destructor manually first.
*/
free(raw_buffer);
return 0;
}
Granted, it's not idiomatic C++ as others have observed, but if the struct is part of legacy code it might be the most straightforward option.
Correctness of the above sample program has only been checked with valgrind using dummy definitions of the structs, your mileage may vary.
If it is fixed size write:
typedef struct
{
char SmType;
char SRes;
float SParm;
float EParm;
WORD Count;
char Flags;
char unused;
GPOINT2 Nodes[4];
} GPATH2;
if not fixed then change declaration to
GPOINT2* Nodes;
after creation or in constructor do
Nodes = new GPOINT2[size];
if you want to resize it you should use vector<GPOINT2>, because you can't resize array, only create new one. If you decide to do it, don't forget to delete previous one.
also typedef is not needed in c++, you can write
struct GPATH2
{
char SmType;
char SRes;
float SParm;
float EParm;
WORD Count;
char Flags;
char unused;
GPOINT2 Nodes[4];
};
This appears to be a C99 idiom known as the "struct hack". You cannot (in standard C99; some compilers have an extension that allows it) declare a variable with this type, but you can declare pointers to it. You have to allocate objects of this type with malloc, providing extra space for the appropriate number of array elements. If nothing holds a pointer to an array element, you can resize the array with realloc.
Code that needs to be backward compatible with C89 needs to use
GPOINT2 Nodes[1];
as the last member, and take note of this when allocating.
This is very much not idiomatic C++ -- note for instance that you would have to jump through several extra hoops to make new and delete usable -- although I have seen it done. Idiomatic C++ would use vector<GPOINT2> as the last member of the struct.
Arrays of unknown size are not valid as C++ data members. They are valid in C99, and your compiler may be mixing C99 support with C++.
What you can do in C++ is 1) give it a size, 2) use a vector or another container, or 3) ditch both automatic (local variable) and normal dynamic storage in order to control allocation explicitly. The third is particularly cumbersome in C++, especially with non-POD, but possible; example:
struct A {
int const size;
char data[1];
~A() {
// if data was of non-POD type, we'd destruct data[1] to data[size-1] here
}
static auto_ptr<A> create(int size) {
// because new is used, auto_ptr's use of delete is fine
// consider another smart pointer type that allows specifying a deleter
A *p = ::operator new(sizeof(A) + (size - 1) * sizeof(char));
try { // not necessary in our case, but is if A's ctor can throw
new(p) A(size);
}
catch (...) {
::operator delete(p);
throw;
}
return auto_ptr<A>(p);
}
private:
A(int size) : size (size) {
// if data was of non-POD type, we'd construct here, being very careful
// of exception safety
}
A(A const &other); // be careful if you define these,
A& operator=(A const &other); // but it likely makes sense to forbid them
void* operator new(size_t size); // doesn't prevent all erroneous uses,
void* operator new[](size_t size); // but this is a start
};
Note you cannot trust sizeof(A) any where else in the code, and using an array of size 1 guarantees alignment (matters when the type isn't char).
This type of structure is not trivially useable on the stack, you'll have to malloc it. the significant thing to know is that sizeof(GPATH2) doesn't include the trailing array. so to create one, you'd do something like this:
GPATH2 *somePath;
size_t numPoints;
numPoints = 4;
somePath = malloc(sizeof(GPATH2) + numPoints*sizeof(GPOINT2));
I'm guessing GPATH2.Count is the number of elements in the Nodes array, so if it's up to you to initialize that, be sure and set somePath->Count = numPoints; at some point. If I'm mistaken, and the convention used is to null terminate the array, then you would do things just a little different:
somePath = malloc(sizeof(GPATH2) + (numPoints+1)*sizeof(GPOINT2));
somePath->Nodes[numPoints] = Some_Sentinel_Value;
make darn sure you know which convention the library uses.
As other folks have mentioned, realloc() can be used to resize the struct, but it will invalidate old pointers to the struct, so make sure you aren't keeping extra copies of it (like passing it to the library).
I want to dynamically allocate a C struct:
typedef struct {
short *offset;
char *values;
} swc;
Both 'offset' and 'values' are supposed to be arrays, but their size is unknown until runtime.
How can I dynamically allocate memory for my struct and the struct's arrays?
swc *a = (swc*)malloc(sizeof(swc));
a->offset = (short*)malloc(sizeof(short)*n);
a->values = (char*)malloc(sizeof(char)*n);
Where n = the number of items in each array and a is the address of the newly allocated data structure. Don't forget to free() offsets and values before free()'ing a.
In C:
swc *s = malloc(sizeof *s); // assuming you're creating a single instance of swc
if (s)
{
s->offset = malloc(sizeof *(s->offset) * number_of_offset_elements);
s->values = malloc(sizeof *(s->values) * number_of_value_elements);
}
In C++:
try
{
swc *s = new swc;
s->offset = new short[number_of_offset_elements];
s->values = new char[number_of_value_elements];
}
catch(...)
{
...
}
Note that in C++, you might be better off using vectors as opposed to dynamically allocated buffers:
struct swc
{
std::vector<short> offset;
std::vector<char> values;
};
swc *a = new swc;
Question: is values supposed to be an array of individual characters or an array of strings? That would change things a bit.
EDIT
The more I think about it, the less satisfied I am with the C++ answer; the right way to do this sort of thing in C++ (assuming you need dynamically allocated buffers as opposed to vectors, which you probably don't) is to perform the memory allocation for offset and values as part of a constructor within the struct type, and have a destructor deallocate those elements when the struct instance is destroyed (either by a delete or by going out of scope).
struct swc
{
swc(size_t numOffset = SOME_DEFAULT_VALUE,
size_t numValues = SOME_OTHER_DEFAULT_VALUE)
{
m_offset = new short[numOffset];
m_values = new char[numValues];
}
~swc()
{
delete[] m_offset;
delete[] m_values;
}
short *m_offset;
char *m_values;
};
void foo(void)
{
swc *a = new swc(10,20); // m_offset and m_values allocated as
// part of the constructor
swc b; // uses default sizes for m_offset and m_values
...
a->m_offset[0] = 1;
a->m_values[0] = 'a';
b.m_offset[0] = 2;
b.m_values[0] = 'b';
...
delete a; // handles freeing m_offset and m_values
// b's members are deallocated when it goes out of scope
}
You have to do it seperately. First allocate the struct, then the memory for the arrays.
In C:
swc *pSwc = malloc(sizeof(swc));
pSwc->offset = malloc(sizeof(short)*offsetArrayLength);
pSwc->values = malloc(valuesArrayLength);
In C++, you shouldn't be doing anything like that.
In C:
typedef struct
{
short *offset;
char *values;
} swc;
/// Pre-Condition: None
/// Post-Condition: On failure will return NULL.
/// On Success a valid pointer is returned where
/// offset[0-n) and values[0-n) are legally de-refrancable.
/// Ownership of this memory is returned to the caller who
/// is responsible for destroying it via destroy_swc()
swc *create_swc(unsigned int size)
{
swc *data = (swc*) malloc(sizeof(swc));
if (data)
{
data->offset = (short*)malloc(sizeof(short)*n);
data->values = (char*) malloc(sizeof(char) *n);
}
if ((data != NULL) && (size != 0) && ((data->offset == NULL) || (data->values == NULL)))
{
// Partially created object is dangerous and of no use.
destroy_swc(data);
data = NULL;
}
return data;
}
void destroy_swc(swc* data)
{
free(data->offset);
free(data->values);
free(data);
}
In C++
struct swc
{
std::vector<short> offset;
std::vector<char> values;
swc(unsigned int size)
:offset(size)
,values(size)
{}
};
You will need a function to do this.
Something like (my C/C++ is rusty)
swc* makeStruct(int offsetCount, int valuesCount) {
swc *ans = new swc();
ans->offset = new short[offsetCount];
ans->values = new char[valuesCount];
return ans;
}
myNewStruct = makeStruct(4, 20);
Syntax may be a bit off but that is generally what you are going to need. If you're using C++ then you probably want a class with a constructor taking the 2 args instead of the makeStruct but doing something very similar.
One thing to add to the many correct answers here: you can malloc an over-sized structure to accommodate a variable sized array in the last member.
struct foo {
short* offset;
char values[0]
};
and later
struct *foo foo1 = malloc(sizeof(struct foo)+30); // takes advantage of sizeof(char)==1
to get room for 30 objects in the values array. You would still need to do
foo1->offsets = malloc(30*sizeof(short));
if you want them to use the same size arrays.
I generally wouldn't actually do this (maintenance nightmare if the structure ever needs to expand), but it is a tool in the kit.
[code here in c. You'll need to cast the malloc's (or better use new and RAII idioms) in c++]
swc* a = malloc(sizeof(*a));
a->offset = calloc(n, sizeof(*(a->offset)));
a->values = calloc(n, sizeof(*(a->values)));
You should not cast void* in c... in c++ you must!
Use malloc function or calloc to allocate memory dynamically .
and search it on google to get examples.
The calloc function initializes allocated memory to zero.
Since nobody has mentioned it yet, sometimes it is nice to grab this chunk of memory in one allocation so you only have to call free() on one thing:
swc* AllocSWC(int items)
{
int size = sizeof(swc); // for the struct itself
size += (items * sizeof(short)); // for the array of shorts
size += (items * sizeof(char)); // for the array of chars
swc* p = (swc*)malloc(size);
memset(p, 0, size);
p->offset = (short*)((char*)swc + sizeof(swc)); // array of shorts begins immediately after the struct
p->values = (char*)((char*)swc + sizeof(swc) + items * sizeof(short)); // array of chars begins immediately after the array of shorts
return p;
}
Of course this is a bit more difficult to read and maintain (especially if you dynamically resize the arrays after it is first allocated). Just an alternative method I've seen used in a number of places.
Most of the answers are correct. I would like to add something that you haven't explicitly asked but might also be important.
C / C++ arrays don't store their own size in memory. Thus, unless you want offset and values to have compile-time defined values (and, in that case, it's better to use fixed-size arrays), you might want to store the sizes of both arrays in the struct.
typedef struct tagswc {
short *offset;
char *values;
// EDIT: Changed int to size_t, thanks Chris Lutz!
size_t offset_count;
size_t values_count; // You don't need this one if values is a C string.
} swc;
DISCLAIMER: I might be wrong. For example, if all offsets of all swc instances have the same size, it would be better to store offset_count as a global member, not as a member of the struct. The same can be said about values and values_count. Also, if values is a C string, you don't need to store its size, but beware of Schlemiel the painter-like problems.
You want to use malloc to allocate the memory, and probably also sizeof() to allocate the correct amount of space.
Something like:
structVariable = (*swc) malloc(sizeof(swc));
Should do the trick.
In addition to the above, I would like to add freeing up the allocated memory as below.,
typedef struct {
short *offset;
char *values;
} swc;
swc* createStructure(int Count1, int Count2) {
swc *s1 = new swc();
s1->offset = new short[Count1];
s1->values = new char[Count2];
return s1;
}
int _tmain(int argc, _TCHAR* argv[])
{
swc *mystruct;
mystruct = createStructure(11, 11);
delete[] mystruct->offset;
delete[] mystruct->values;
delete mystruct;
return 0;
}
**If** you will not be resizing the arrays, then you can get away with a single call to malloc().
swc *new_swc (int m, int n) {
swc *p;
p = malloc (sizeof (*p) + m * sizeof (p->offset[0]) + n * sizeof (p->values[0]);
p->offset = (short *) &p[1];
p->values = (char *) &p->offset[m];
return p;
}
You can then free it with a single call to free().
(In general, there are alignment considerations to take into account, but for an array of shorts followed by an array of chars, you will be fine.)
In the following lines of code, I need to adjust the pointer pm by an offset in bytes in one of its fields. Is there an better/easier way to do this, than incessantly casting back and forth from char * and PartitionMap * such that the pointer arithmetic still works out?
PartitionMap *pm(reinterpret_cast<PartitionMap *>(partitionMaps));
for ( ; index > 0 ; --index)
{
pm = (PartitionMap *)(((char *)pm) + pm->partitionMapLength);
}
return pm;
For those that can't grok from the code, it's looping through variable length descriptors in a buffer that inherit from PartitionMap.
Also for those concerned, partitionMapLength always returns lengths that are supported by the system this runs on. The data I'm traversing conforms to the UDF specification.
I often use these templates for this:
template<typename T>
T *add_pointer(T *p, unsigned int n) {
return reinterpret_cast<T *>(reinterpret_cast<char *>(p) + n);
}
template<typename T>
const T *add_pointer(const T *p, unsigned int n) {
return reinterpret_cast<const T *>(reinterpret_cast<const char *>(p) + n);
}
They maintain the type, but add single bytes to them, for example:
T *x = add_pointer(x, 1); // increments x by one byte, regardless of the type of x
Casting is the only way, whether it's to a char* or intptr_t or other some such type, and then to your final type.
You can of course just keep two variables around: a char * to step through the buffer and a PartitionMap * to access it. Makes it a little clearer what's going on.
for (char *ptr = ??, pm = (PartitionMap *)ptr ; index > 0 ; --index)
{
ptr += pm->partitionMapLength;
pm = (PartitionMap *)ptr;
}
return pm;
As others have mentioned you need the casts, but you can hide the ugliness in a macro or function. However, one other thing to keep in mind is alignment requirements. On most processors you can't simply increment a pointer to a type by an arbitrary number of bytes and cast the result back into a pointer to the original type without problems accessing the struct through the new pointer due to misalignment.
One of the few architectures (even if it is about the most popular) that will let you get away with it is the x86 architecture. However, even if you're writing for Windows, you'll want to take this problem into account - Win64 does enforce alignment requirements.
So even accessing the partitionMapLength member through the pointer might crash your program.
You might be able to easily work around this problem using a compiler extension like __unaligned on Windows:
PartitionMap __unaliged *pm(reinterpret_cast<PartitionMap *>(partitionMaps));
for ( ; index > 0 ; --index)
{
pm = (PartitionMap __unaligned *)(((char *)pm) + pm->partitionMapLength);
}
return pm;
Or you can copy the potentially unaligned data into a properly aligned struct:
PartitionMap *pm(reinterpret_cast<PartitionMap *>(partitionMaps));
char* p = reinterpret_cast<char*>( pm);
ParititionMap tmpMap;
for ( ; index > 0 ; --index)
{
p += pm->partitionMapLength;
memcpy( &tmpMap, p, sizeof( newMap));
pm = &tmpMap;
}
// you may need a more spohisticated copy to return something useful
size_t siz = pm->partitionMapLength;
pm = reinterpret_cast<PartitionMap*>( malloc( siz));
if (pm) {
memcpy( pm, p, siz);
}
return pm;
The casting has to be done, but it makes the code nearly unreadable. For readability's sake, isolate it in a static inline function.
What is puzzling me is why you have 'partitionMapLength' in bytes?
Wouldn't it be better if it was in 'partitionMap' units since you anyway cast it?
PartitionMap *pmBase(reinterpret_cast<PartitionMap *>(partitionMaps));
PartitionMap *pm;
...
pm = pmBase + index; // just guessing about your 'index' variable here
Both C and C++ allow you to iterate through an array via pointers and ++:
#include <iostream>
int[] arry = { 0, 1, 2, 3 };
int* ptr = arry;
while (*ptr != 3) {
std::cout << *ptr << '\n';
++ptr;
}
For this to work, adding to pointers is defined to take the memory address stored in the pointer and then add the sizeof whatever the type is times the value being added. For instance, in our example ++ptr adds 1 * sizeof(int) to the memory address stored in ptr.
If you have a pointer to a type, and want to advance a particular number of bytes from that spot, the only way to do so is to cast to char* (because sizeof(char) is defined to be one).