Accessing Elements of Structure with a Pointer?

Started by
24 comments, last by ApochPiQ 12 years, 7 months ago

Your solution is not generalized; you have to hard-code it for every structure member. The OP is looking for something more flexible.

Also, your solution is not correct. pyValue should be assigned to (int*)(pLocation + offsetof(BALL, y)), not (...pBall...).


Exactly. Thank you for being aware of this. I am intrigued by the offsetof(...) function however, like if I have a beer I could perhaps just take the time to type up the "offset of" command for the 50 lines of the struct I have, then use that. However, if a more generalized solution exists that'd be fantastic. The packing is also an intriguing idea, I'd have to take the time to study this I feel.

To Serapth, this is posted in the For Beginners, but I am not exactly a beginner, which isn't to say that I am an all knowing programming guru... I just thought this was a basic question and that somehow the solution fell out of my brain ages ago.

You guys are doing great with this post, thank you so much. Does anyone else have any ideas?
AfroFire | Brin"The only thing that interferes with my learning is my education."-Albert Einstein
Advertisement
This is untested and evil, so only use it if you have to ;-)

My C is also very rusty, so this may not compile in vanilla C; it should be easy to adapt from the C++ conventions though.



struct MemberInfo
{
void* array;
unsigned size;
};

void AOStoSOA(void* arraybegin, unsigned arraycount, unsigned arraystride, MemberInfo outarrays[], unsigned nummembers)
{
char* arrayptr = (char*)(arraybegin);

for(unsigned i = 0; i < arraycount; ++i)
{
unsigned offset = 0;

for(unsigned j = 0; j < nummembers; ++j)
{
memcpy(&outarrays[j].array, arrayptr + offset, outarrays[j].size);
offset += outarrays[j].size;
}

arrayptr += arraystride;
}
}

// PACKING IS MANDATORY HERE
#pragma pack(push)
#pragma pack(1)
struct Foo
{
int Test;
char Blah;
};
#pragma pack(pop)

struct SOAForm
{
int* TestArray;
char* BlahArray;
};

#define COUNT 10

void SomeFunction()
{
Foo aos[COUNT];

SOAForm soa;
soa.TestArray = malloc(sizeof(int) * COUNT);
soa.BlahArray = malloc(sizeof(char) * COUNT);

MemberInfo arrays[] =
{
{ soa.TestArray, sizeof(int) },
{ soa.BlahArray, sizeof(char) }
};

AOStoSOA(&aos[0], COUNT, (char*)(&aos[1]) - (char*)(&aos[0]), arrays, 2);

printf("Third Blah is '%c'\n", soa.BlahArray[2]);

free(soa.TestArray);
free(soa.BlahArray);
}



You could automatically generate most of this code using macros, as I alluded to above. If you're interested in that route, I might have time to hack something up later this afternoon.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]


This is untested and evil, so only use it if you have to ;-)

My C is also very rusty, so this may not compile in vanilla C; it should be easy to adapt from the C++ conventions though.



struct MemberInfo
{
void* array;
unsigned size;
};

void AOStoSOA(void* arraybegin, unsigned arraycount, unsigned arraystride, MemberInfo outarrays[], unsigned nummembers)
{
char* arrayptr = (char*)(arraybegin);

for(unsigned i = 0; i < arraycount; ++i)
{
unsigned offset = 0;

for(unsigned j = 0; j < nummembers; ++j)
{
memcpy(&outarrays[j].array, arrayptr + offset, outarrays[j].size);
offset += outarrays[j].size;
}

arrayptr += arraystride;
}
}

// PACKING IS MANDATORY HERE
#pragma pack(push)
#pragma pack(1)
struct Foo
{
int Test;
char Blah;
};
#pragma pack(pop)

struct SOAForm
{
int* TestArray;
char* BlahArray;
};

#define COUNT 10

void SomeFunction()
{
Foo aos[COUNT];

SOAForm soa;
soa.TestArray = malloc(sizeof(int) * COUNT);
soa.BlahArray = malloc(sizeof(char) * COUNT);

MemberInfo arrays[] =
{
{ soa.TestArray, sizeof(int) },
{ soa.BlahArray, sizeof(char) }
};

AOStoSOA(&aos[0], COUNT, (char*)(&aos[1]) - (char*)(&aos[0]), arrays, 2);

printf("Third Blah is '%c'\n", soa.BlahArray[2]);

free(soa.TestArray);
free(soa.BlahArray);
}



You could automatically generate most of this code using macros, as I alluded to above. If you're interested in that route, I might have time to hack something up later this afternoon.


Holy shit, you are the man.

This is pretty much exactly what I was going for, you took the freakin' code right out of my mind!
Just out of curiosity however, you use the following to get the stride:
(char*)(&aos[1]) - (char*)(&aos[0])

Why not just do sizeof(Foo), it's not likely there is padding within the array, right?

Additionally, if you'd like to do the macro code it'd be mostly academic, but for people who might need something like this, it would be a good reference post.

I think this would be good enough for me though, I don't even know how to convey how grateful I am. Just doing some prelim tests, I am convinced your solution works (if there are any nit picky bugs I could figure them out from here).

I "liked" your posts, but I am not sure how the reputation granting works anymore, is this what reputation has become here?

Thanks a million more times.
AfroFire | Brin"The only thing that interferes with my learning is my education."-Albert Einstein
I don't honestly remember the C standard regarding padding between entries in an array. I know if you have a specified alignment (e.g. for arrays used by SIMD instructions) then you can have "dead" bytes between array entries, outside of struct member padding. That was done out of paranoia because it will definitely work, whereas just sizeof() might give you the wrong stride in certain obscure cases.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]



typedef struct {
void* array;
unsigned size;
} MemberInfo;

void AOStoSOA(void* arraybegin, unsigned int arraycount, unsigned int arraystride, MemberInfo outarrays[], unsigned int nummembers)
{
char* arrayptr = (char*)(arraybegin);

unsigned int i = 0;
for(i = 0; i < arraycount; ++i)
{
unsigned offset = 0;
unsigned int j;
for(j = 0; j < nummembers; ++j)
{
int *c = arrayptr;

memcpy(&(outarrays[j].array[i*outarrays[j].size]), arrayptr + offset, outarrays[j].size);
offset += outarrays[j].size;
}

arrayptr += arraystride;
}
}

// PACKING IS MANDATORY HERE
#pragma pack(push)
#pragma pack(1)
typedef struct {
int Test;
char Blah;
} Foo;
#pragma pack(pop)

typedef struct {
int* TestArray;
char* BlahArray;
} SOAForm;

#define COUNT 3

int main(int argc, char *argv[])
{
Foo aos[COUNT];

// EXAMPLE DATA
aos[0].Test = 123;
aos[0].Blah = 'a';
aos[2].Test = 456;
aos[2].Blah = 'd';
aos[1].Test = 789;
aos[1].Blah = 'c';

SOAForm soa;
soa.TestArray = malloc(sizeof(int) * COUNT);
soa.BlahArray = malloc(sizeof(char) * COUNT);

MemberInfo arrays[] =
{
{ soa.TestArray, sizeof(int) },
{ soa.BlahArray, sizeof(char) }
};


AOStoSOA(&aos[0], COUNT, (char*)(&aos[1]) - (char*)(&aos[0]), arrays, 2);

printf("Third Blah is '%c'\n", soa.BlahArray[2]);

free(soa.TestArray);
free(soa.BlahArray);
}


Here is an updated version of the code. The most important addendum was to the line:

memcpy(&(outarrays[j].array[i*outarrays[j].size]), arrayptr + offset, outarrays[j].size);

Where there was a problem with the destination parameter (first parameter) of the memcpy. Specifically, it was incrementing in ones when it should have been incrementing in terms of the size of the data being stored in that location.

That's pretty much it though, everything else is just nit picky stuff, or the compiler I was using was unhappy with it.

Thanks a whole bunch all over again Apoch.
AfroFire | Brin"The only thing that interferes with my learning is my education."-Albert Einstein
Good catch :-)

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

This topic is closed to new replies.

Advertisement