Jump to content
  • Advertisement
Sign in to follow this  
AfroFire

Accessing Elements of Structure with a Pointer?

This topic is 2640 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Is it possible to access the individual elements of a structure using some offset from the current memory address?

For example, if I had a struct that was as such:

typedef struct {
int x;
int y;
int z;
} BALL;

BALL *a = malloc(sizeof(BALL));


Instead of calling a->y I was wondering if there was a way I could do something like *(a+offset) where offset is sizeof(int) or something, and then it would access the y element. So far nothing I do seems to work. I could've sworn that my understanding of the way struct was laid out meant that the struct was contiguously stored in memory or something.

Share this post


Link to post
Share on other sites
Advertisement
Since the pointer, a, points to type BALL, any offset applied to a is going to be applied in chunks the size of ball. ie, it thinks a+offset is an array access into an array of BALLS. You would need to cast a to a char ptr in order to do byte-level offsetting.

Out of curiosity, why is -> indirection unsuitable?

Share this post


Link to post
Share on other sites
The offset of a variable in a structure can be found as follows:

BALLS * pbThis = new BALLS;
#1: Convert the pointer to a numeric value for arithmetic.
UINT_PTR uiptrBaseAddr = reinterpret_cast<UINT_PTR>(pbThis);

#2: Convert the address of the member to an integer-form numeric value.
UINT_PTR uiptrMemberAddr = reinterpret_cast<UINT_PTR>(&pbThis->y);

#3: Subtract them.
UINT_PTR uiptrOffset = uiptrMemberAddr - uiptrBaseAddr; // uiptrOffset = 4 in Microsoft Visual Studio (sizeof( int )).


To then access that variable via offset instead of ->:
int iY = (*reinterpret_cast<int *>(uiptrBaseAddr + uiptrOffset));

Or without the predetermined offsets:
int iY = (*reinterpret_cast<int *>(reinterpret_cast<UINT_PTR>(pbThis) + sizeof( int )));



I did not provide this solution because I think you should be doing this. This is for learning only or for making a script system in which you can send member offsets to the script and it can use offsets to access those members.


L. Spiro

Share this post


Link to post
Share on other sites

Since the pointer, a, points to type BALL, any offset applied to a is going to be applied in chunks the size of ball. ie, it thinks a+offset is an array access into an array of BALLS. You would need to cast a to a char ptr in order to do byte-level offsetting.

Out of curiosity, why is -> indirection unsuitable?


This isn't even a game development related question. I just feel like this is one of the most trust worthy sites to ask programming related questions. Thank you for pointing out the +1 being equal to the size of BALL. I will do the casting to char bit.

The reason why -> is unsuitable is because I am writing a function that has to turn large arrays of structures in to arrays of the constituents of the structure. So for example, I'd like a giant array of x properties, so I'd like to be able to iterate through a list of BALLs and store the x values in to an array of integers that are equal to the x values. That's simple enough when I have an x, y, and z, but if this so-called struct had say 50 properties, I'd have to write some code for all of them. This little bit of help you provided is going to help me write a general function that does the task, and all I want to have to do is provide an offset, and it will just go to that offset and create an array from that.

Again, thank you for the very quick help.

Share this post


Link to post
Share on other sites

The offset of a variable in a structure can be found as follows:

BALLS * pbThis = new BALLS;
#1: Convert the pointer to a numeric value for arithmetic.
UINT_PTR uiptrBaseAddr = reinterpret_cast<UINT_PTR>(pbThis);

#2: Convert the address of the member to an integer-form numeric value.
UINT_PTR uiptrMemberAddr = reinterpret_cast<UINT_PTR>(&pbThis->y);

#3: Subtract them.
UINT_PTR uiptrOffset = uiptrMemberAddr - uiptrBaseAddr; // uiptrOffset = 4 in Microsoft Visual Studio (sizeof( int )).


To then access that variable via offset instead of ->:
int iY = (*reinterpret_cast<int *>(uiptrBaseAddr + uiptrOffset));

Or without the predetermined offsets:
int iY = (*reinterpret_cast<int *>(reinterpret_cast<UINT_PTR>(pbThis) + sizeof( int )));



I did not provide this solution because I think you should be doing this. This is for learning only or for making a script system in which you can send member offsets to the script and it can use offsets to access those members.


L. Spiro


I have never seen the UINT_PTR before, and while this isn't your fault, my code is in C, and if I can recall correctly, the reinterpret_cast< ... > is a C++ thing, right?

Either way, I am content with (char*) casting.

Thanks to you as well!



Share this post


Link to post
Share on other sites
UINT_PTR exists within the Win32 SDK to provide an unsigned integer whose size is always the same size as a pointer.
Many people naively convert pointers to int, unsigned long, DWORD, and a number of other atrocities.
If you need an integer form of a pointer, always cast to UINT_PTR.

And in C, you can use a C cast:
UINT_PTR uiptrBaseAddr = (UINT_PTR)pbThis;


L. Spiro

Share this post


Link to post
Share on other sites

Either way, I am content with (char*) casting.


Compiler is free to insert padding between items so simply assuming that the second int member is at pointer+sizeof(int) from pointer is not guaranteed. It is likely with ints as if padding is done, it is probably going to aligned to machine word boundaries, but not for sure.

So code that "works" could suddenly break if you change compiler, or if your compiler updates, or if you add another member to the struct etc etc.

Share this post


Link to post
Share on other sites

[quote name='AfroFire' timestamp='1316584253' post='4864114']
Either way, I am content with (char*) casting.


Compiler is free to insert padding between items so simply assuming that the second int member is at pointer+sizeof(int) from pointer is not guaranteed. It is likely with ints as if padding is done, it is probably going to aligned to machine word boundaries, but not for sure.

So code that "works" could suddenly break if you change compiler, or if your compiler updates, or if you add another member to the struct etc etc.
[/quote]

Well shit, then what can I do? This is a very real concern.

Share this post


Link to post
Share on other sites

UINT_PTR exists within the Win32 SDK to provide an unsigned integer whose size is always the same size as a pointer.
Many people naively convert pointers to int, unsigned long, DWORD, and a number of other atrocities.
If you need an integer form of a pointer, always cast to UINT_PTR.

And in C, you can use a C cast:
UINT_PTR uiptrBaseAddr = (UINT_PTR)pbThis;


L. Spiro


Ah, well this is code that is being run on super computers that will more than likely be running Linux... is there a non Win32 version?

Share this post


Link to post
Share on other sites

The offset of a variable in a structure can be found as follows:BALLS * pbThis = new BALLS;#1: Convert the address of the member to a pointer to a byte-sized type
char* baseAddr = reinterpret_cast<char*>(pbThis);#2: Convert the address of the member to a pointer to a byte-sized type
char* memberAddr = reinterpret_cast<char*>(&pbThis->y);#3: Subtract them.
ptrdiff_t offset = memberAddr - baseAddr; // offset = 4 in Microsoft Visual Studio (sizeof( int )).To then access that variable via offset instead of ->:int iY = (*reinterpret_cast<int *>(baseAddr + offset));
^^Standard-compliant version

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!