0

Lets pretend we have the following code:

typedef struct
{
    int a1;
    int a2;
} a_struct;

int prev (int a2)
{
    int* p = &A_STRUCT-4;
    return *p;
}

int main(void)
{
    a_struct aStruct[] = {5, 10}; // Array-type initializing

    printf("aStruct.a1 = %i", prev(aStruct->a2));

    return 1;
}

I am trying to access aStruct.a1's value by accessing aStruct.a2 memory address and dereferencing it, however following this way, it leads to an u/b and runtime complications. With one word, it doesn't work. What am i doing wrong?

Corelation
  • 79
  • 7
  • It isn't reliable, but if you call `prev(&aStruct->a2)` and write `int prev(int *a2) { int *p1 = a2 - 1; return *p1; }` it should work. Given a non-pointer argument to `prev()`, there is nothing you can do. – Jonathan Leffler Nov 05 '14 at 20:54

2 Answers2

2

There are two separate issues. First, you pass a value of the field, not its address.

Second, assuming that you have address of a field of struct, you could get a pointer to the struct itself with help of offsetof macro:

int prev(int* pa2)
{
    size_t offset = offsetof(a_struct, a2);
    a_struct* p = (a_struct*)((char*)pa2 - offset);
    return p->a1;
}

....

printf("aStruct.a1 = %i\n", prev(&aStruct->a2));
AlexD
  • 32,156
  • 3
  • 71
  • 65
  • `size_t offset = (int)offsetof(a_struct, a2);` I can't allow that, whatever it is. I need to build the macro manually. – Corelation Nov 05 '14 at 20:19
  • @Corelation Just look how `offsetof` macro is implemented by your compiler. – AlexD Nov 05 '14 at 20:22
  • unfortunatelly its not. I am coding on a closed-platform SDL window runtime. I can not include extra libraries and the language version is C89. – Corelation Nov 05 '14 at 20:23
  • @Corelation Try something like this: `#define my_offsetof(s,m) (size_t)(char*)(&(((s*)0)->m))` – AlexD Nov 05 '14 at 20:27
  • It doesn't even compile. – Corelation Nov 05 '14 at 20:32
  • It compiles for me. Which error do you get? And another question - are you saying that your `stddef.h` does not have `offsetof`? – AlexD Nov 05 '14 at 20:35
  • I can not include anything other then `stdlib.h` `stdio` and `math.h` I get incopatible types at `size_t offset = (int)offsetof(a_struct, a2);` and unexplained declaration at the next line. – Corelation Nov 05 '14 at 20:38
  • 1. Do not _include_ `stddef.h`, just check the content. 2. `(int)` is removed. Try now. – AlexD Nov 05 '14 at 20:43
  • It worked. It looks kinda complicated, is that the only way? Is there any explanation? (It would be really good, because the code is a mess) – Corelation Nov 05 '14 at 20:49
  • `offsetof` is defined in `` and you would need to include that. – Jonathan Leffler Nov 05 '14 at 20:52
  • @JonathanLeffler OP said that it is not allowed to include `` and that the macro should be done by hand. – AlexD Nov 05 '14 at 20:54
  • And it worked as i mentioed, but i feel awful for not understanding this. I'd be good if you could provide an explanation though.. pure code is spoon-feeding considered anyway. I need to learn this for not asking more and more.. It'll be useful. – Corelation Nov 05 '14 at 20:58
  • @Corelation Do you want to understand how the macro itself works, or why we use the macro? – AlexD Nov 05 '14 at 21:00
  • I was stating explicitly what is implied by the other comments - that's all. While you can do the job with `offsetof`, you can also do it (approximately equally portably) without, as shown in my comment to the question. I'm not confident I'd want to rely on it everywhere, though I don't see a reason why it would fail, either. – Jonathan Leffler Nov 05 '14 at 21:00
  • @JonathanLeffler It could fail because `struct` is not guaranteed to have sequential layout. I doubt that in our case padding takes place, but it is possible in theory. – AlexD Nov 05 '14 at 21:05
  • `#pragma pack?` Anyway.. i need to understand how the entire scheme works. – Corelation Nov 05 '14 at 21:08
  • @Corelation `offsetof` gives you the offset of a field from the beginning of the structure. So, we deduct that offset from the pointer to the field, and get the pointer to the structure. Then we just use the pointer to the structure to access any other field. Implementation of `offsetof` is something compiler specific. In my sample it takes an address of a field as if the struct starts from `NULL`. However, dereferencing `NULL` (I guess even in such scenario) is undefined behavior. So, once again, use the macro of your compiler. – AlexD Nov 05 '14 at 21:23
0

There are multiple errors:

typedef struct
{
    int a1;
    int a2;
} a_struct;

int prev (a_struct A_STRUCT) // <== This should be void* A_STRUCT since you are receiving an address.
{
    int* p = &A_STRUCT-4; // <== This should be (char *)A_STRUCT - sizeof(int). Read about pointer arithmetic.
    return *p;
}

int main(void)
{
    a_struct aStruct[] = {5, 10}; // Array-type initializing

    printf("aStruct.a1 = %i", prev(aStruct->a2)); // <== This should be prev(&aStruct->a2) since you are passing the address. 

    return 1;
}
user1952500
  • 6,611
  • 3
  • 24
  • 37
  • No, fixed the `prev` parameter it was a mistake of mine. I don't just copy/paste the thing i do.. Wanted to provide a brief example. – Corelation Nov 05 '14 at 20:15
  • @user1952500 `- sizeof(int)` does not look correct. There is no guarantee that the layout is sequential. – AlexD Nov 05 '14 at 20:32
  • @AlexD, is there no guarantee for a POD structure like struct as well ? – user1952500 Nov 06 '14 at 00:21
  • @AlexD, the link points to non-POD structures. For example, a link from wiki (http://www.fnal.gov/docs/working-groups/fpcltf/Pkg/ISOcxx/doc/POD.html) says: Layout The bytes constituting a POD object are contiguous [§1.8, ¶5]. "POD-struct ... types are layout-compatible if they have the same number of members, and corresponding members (in order) have layout-compatible types" [§9.2, ¶14]. POD-union ... types are layout-compatible if they have the same number of members, and corresponding members (in any order) have layout-compatible types" [§9.2, ¶15]. Classes are not POD structures. – user1952500 Nov 06 '14 at 01:58
  • @user1952500 I did not mean classes. I meant `struct some_object` from the linked answer. It may have (although not necessarily) padding after `char c`. It is much less likely to get padding in our case, but still, it is not guaranteed, as far as I understand. – AlexD Nov 06 '14 at 02:07
  • @AlexD, there is padding only in case the size is not aligned to the addressing boundary. That will not happen for the current struct and is not even compiler dependent in this case. – user1952500 Nov 06 '14 at 02:11
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/64360/discussion-between-alexd-and-user1952500). – AlexD Nov 06 '14 at 02:25