1
\$\begingroup\$

This sounds like a little too far fetched, but is there any possibility to find the address of a structure, if the address of one of it's members is known? The struct itself contains different data types, and is 2 bytes aligned. I am working on an embedded target, with DIAB compiler.

Here is the end application. There is an external device with direct R/W access to the RAM memory. If this device modifies a memory location that happens to be within a structure, I need to know which structure was it(or it's starting address) for some processing to be done later.

Update: A direct solution to this problem is difficult. The answer with some relevant discussions regarding the issue has been chosen.

Thanks!

\$\endgroup\$
  • 1
    \$\begingroup\$ If you know which element was changed, you can calculate the start of the structure. \$\endgroup\$ – A.R.C. Nov 28 '18 at 12:01
  • \$\begingroup\$ Unfortunately no, all I know is an address from the whole memory area(which is also the address of a structure member ) at which the data was modified. \$\endgroup\$ – Soju T Varghese Nov 28 '18 at 12:09
  • \$\begingroup\$ For every structure you know the start address and end address (which is start address + sizeof(the structure)). If your memory address lies in this range then that structure has been changed. \$\endgroup\$ – Steve G Nov 28 '18 at 14:42
  • \$\begingroup\$ The way to do this reliably is to map the structs to an area of memory, with a known alignment per structure. Meaning the structs must all be of the same type. \$\endgroup\$ – Lundin Nov 29 '18 at 9:12
6
\$\begingroup\$

There's an old trick in C that allows you to #define a macro that does that. The trick goes:

  1. Say your struct type is called struc_t. Create a pointer to one these and point it to any address:

    struc_t *base_pointer = (struc_t*) 0;
    
  2. Say the member whose address you know is struc_t.member; then you just get the address of that:

    char *elem_pointer = &(base_pointer->member);
    
  3. Then, you get the offset by a funky mathematical operation called subtraction:

    size_t offset = (elem_pointer-base_pointer);
    
  4. Now, you can subtract offset from your element's address. Done!

If your processor's toolchain is halfway decent, it'll support the offsetof macro. (In fact, that's C89, see man offsetoff).

\$\endgroup\$
  • \$\begingroup\$ Is there any possibility if there are multiple structure types and struc_t is unkown when i receive the elem_pointer in runtime? \$\endgroup\$ – Soju T Varghese Nov 28 '18 at 12:31
  • 1
    \$\begingroup\$ No. Where should that information come from? \$\endgroup\$ – Marcus Müller Nov 28 '18 at 12:39
  • 2
    \$\begingroup\$ Given that offsetof has been standard C since 1989 and probably de facto standard even earlier, this must be a very old trick. And as such, it went obsolete in the 1980s. Don't teach this - pointer arithmetic isn't even well-defined unless the pointers point into an array. (And the result is of type ptrdiff_t, not size_t.) \$\endgroup\$ – Lundin Nov 28 '18 at 15:31
  • 1
    \$\begingroup\$ @Lundin I do tend to agree, and on StackOverflow, I'd have said the same and added an explanation on why to use standard functions. But this is EE, where PIC compilers abound... \$\endgroup\$ – Marcus Müller Nov 28 '18 at 15:53
  • 1
    \$\begingroup\$ @MarcusMüller The sooner embedded sys programmers stop taking crap from "crapilers", the better tools we'll get. I'm in a position where I can dictate that the company should not use microcontrollers from a certain manufacturer because of their bad tool support, and has done so several times. For low volume or cost-sensitive applications, you can't really justify buying the commercial alternatives when the vendor's own tool chain is crap. The solution has become to get a nice ARM toolchain and re-use it for multiple projects. Meaning that things like PIC, AVR, HCS08, STM8 etc won't get used. \$\endgroup\$ – Lundin Nov 29 '18 at 9:05
0
\$\begingroup\$

From another question on stackoverflow it becomes evident that yes, you can find the address of a struct if you know one of its members.

So if you know the start address of your struct array and you know the number of bytes per struct. Then you can use simple division to find out which struct it is.


Example

Everything is in base 10

Let's say we have an array that starts at address 350 and we find one member of an unknown struct at address 482. Let's say that every struct contains 7 bytes of memory.

Then the address of 482 is a part of struct number \$\frac{482-350}{7} \approx 18.85 \rightarrow 18\$.
Everything is rounded down automatically if you just use integers everywhere.

Here I came with the number 7 for the number of bytes per struct, in your case you should use the sizeof command.


Edit

If you need to resort to these kinds of solutions then something is very wrong with your code. Or your control there of. I believe I've solved an XY problem, one of my greatest fears has come true.

I don't see any reality where this solution is the right one, so this solution is clearly a last resort of some kind. If it is due to actual limitations, or the limitation of your imagination, that is the question.

\$\endgroup\$
  • \$\begingroup\$ -1 for your edit. Many dynamic data structures in the Linux kernel use this trick due to the architectural choice made when defining them. That is - you don't pass a void pointer but rather make a list/tree node a member of your structure. \$\endgroup\$ – Jan Dorniak Nov 28 '18 at 21:45
  • \$\begingroup\$ @JanDorniak What is "this trick"? Is it to edit members of unknown structures? - Hmm, I did also say "Or your control there of", oh well. \$\endgroup\$ – Harry Svensson Nov 28 '18 at 21:58
  • \$\begingroup\$ I didn't read thoroughly enough and suggested myself with the other answer (a bad habit: if the title is clear enough skip content of the question). And well... SE locked my vote until you edit the answer. Sorry about that. \$\endgroup\$ – Jan Dorniak Nov 28 '18 at 22:11
  • \$\begingroup\$ @HarrySvensson I had never previously read about the XY problem, so thanks for the mention here. However, I believe, in my question the second paragraph is X and the first is Y, if I am not wrong..? If so, I am not able to think of it as a problem with my code. I would just like to know if any of the structures in RAM were modified by the external device. Because a copy of few of these structures are also saved in an external EEPROM, so if one of them were modified, the EEPROM copy also should be modified before power down. Hope it's clear enough.. \$\endgroup\$ – Soju T Varghese Nov 29 '18 at 9:37
  • 1
    \$\begingroup\$ @HarrySvensson I agree. Infact I am defining the interface for the external device too, therefore I was just looking at this vague possibility of finding out the parent struct(as I mentioned in the question this idea was a little too far fetched ). It's finally decided to pass the struct address too along with the member data. Thanks for your feedbacks! \$\endgroup\$ – Soju T Varghese Dec 3 '18 at 9:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.