Is a Struct's Address the Same as Its First Member's Address

Is a struct's address the same as its first member's address?

Is a struct's address the same as its first member's address?

Yes, this is actually mandated by the C and C++ standards. From the C standard:

6.7.2.1-13. A pointer to a structure object, suitably converted, points to its initial member

The size of your struct should be two bytes. You should not convert a pointer to it to char*, though: instead, you should use memcpy to copy your Bitmask into the buffer that you send over the network.

EDIT Since you use scatter-gather I/O with iovec, you do not need to cast Bitmask to anything: iov_base is void*, so you can simply set iov[0].iov_base = header;

Note: This works only as long as your struct does not contain virtual functions, base classes, etc. (thanks, Timo).

EDIT2

In order to get {0x81, 0x05} in your struct, you should change the order of structure elements as follows:

struct Bitmask {
unsigned char opcode: 4;
unsigned char rsv3: 1;
unsigned char rsv2: 1;
unsigned char rsv1: 1;
unsigned char fin: 1;
unsigned char payload_length: 7;
unsigned char mask: 1;
}

Is pointer to struct a pointer to its first member?

The padding at the start is covered by 6.7.2.1p15 (emphasis mine)

Within a structure object, the non-bit-field members and the units in
which bit-fields reside have addresses that increase in the order in
which they are declared. A pointer to a structure object, suitably
converted, points to its initial member (or if that member is a
bit-field, then to the unit in which it resides), and vice versa.
There may be unnamed padding within a structure object, but not at its
beginning
.

So the address of a struct is the address of of its first member. And following a pointer conversion, you are able to obtain one from the other.

Why do class members have the same address as their object?

Because a pointer to a struct always points to it's first member (as the struct is laid out sequentially).

In C, does a pointer to a structure always point to its first member?

(C1x §6.7.2.1.13: "A pointer to a structure object, suitably
converted, points to its initial member ... and vice versa. There may
be unnamed padding within as structure object, but not at its
beginning.")

NOTE: mange points out, rightfully so, that if you start adding virtual functions to your struct, C++ implements this by tacking the vtable at the start of your struct... which makes my statement (which is true for C) incorrect when you talk about everything you could possibly do with 'structs' in C++.

Why use address of first element of struct, rather than struct itself?

Nobody should do that.
If you rearrange struct members you are in trouble.

Does the C++17 standard guarantee that the address of a union is the same as the address of its members?

Yes.

9.2/19 (12.2/24 in N4659):

If a standard-layout class object has any non-static data members, its address is the same as the address of its first non-static data member.

If the union itself is standard-layout, then the address of the union is the same as its members'.

The addresses of the members are all the same, thanks to 9.5/1 (12.3/2 in N4659):

Each non-static data member is allocated as if it were the sole member of a
struct. All non-static data members of a union object have the same address.

Can I safely interpret the first struct member's address as that of the whole struct?

From C standard

6.7.2.1 Structure and union specifiers

15 . Within a structure object, the non-bit-field members and the units in which bit-fields
reside have addresses that increase in the order in which they are declared. A pointer to a
structure object, suitably converted, points to its initial member
(or if that member is a
bit-field, then to the unit in which it resides), and vice versa. There may be unnamed
padding within a structure object, but not at its beginning.

Emphasis mine

In c accessing first element of the struct using address of the struct and pointers

As already mentioned you can drop your BASE macro as the operators cancel out on pointers.

I cleared up and corrected your code a bit and explained where you where going wrong:

#include <stdio.h>
#include <string.h>

struct animal
{
int walk;
int hear;
};

struct bird
{
struct animal *base;
int fly;
};

void display(struct animal *common)
{
printf("All animal details hear=%d walk=%d\n",common->hear, common->walk);
}

int main()
{
struct bird peacock; // removed ptr suffix, since it is not a pointer
struct animal base ;

base.hear=1;
base.walk=1;

peacock.base= &base;

struct bird *peacockptr = &peacock;
peacockptr->fly=1;

printf("base address using peacock struct %p\n", (void *)*(struct animal **)peacockptr); //This is the address of base using peackockptr
printf("base address animal %p\n", (void *)&base); //This is the address of base

display(&base);
display(*(struct animal **)peacockptr);

return 0;
}

Note that the adress of peackock equals the address of the first element of the struct which is a struct animal *. So you have to cast peacockptr to struct animal ** (because it is pointing to the first element which is of type struct animal *) and then dereference it to get the address of base.

Is it legal Rust to cast a pointer to a struct's first member to a pointer to the struct?

The way you wrote it, currently not; but it is possible to make it work.

Reference to T is only allowed to access T - no more (it has provenance for T). The expression &d.base gives you a reference that is only valid for Base. Using it to access Derived's fields is undefined behavior. It is not clear this is what we want, and there is active discussion about that (also this), but that is the current behavior. There is a good tool named Miri that allows you to check your Rust code for the presence of some (not all!) undefined behavior (you can run it in the playground; Tools->Miri), and indeed it flags your code:

error: Undefined Behavior: trying to reborrow <untagged> for SharedReadOnly permission at alloc1707[0x8], but that tag does not exist in the borrow stack for this location
--> src/main.rs:17:5
|
17 | &*ptr
| ^^^^^
| |
| trying to reborrow <untagged> for SharedReadOnly permission at alloc1707[0x8], but that tag does not exist in the borrow stack for this location
| this error occurs as part of a reborrow at alloc1707[0x0..0x10]
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental
= help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information

= note: inside `get_derived_from_base` at src/main.rs:17:5
note: inside `main` at src/main.rs:31:28
--> src/main.rs:31:28
|
31 | let derived = unsafe { get_derived_from_base(base) }; // defined behaviour?
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^

You can make it work by creating a reference to the whole Derived and casting it to a raw pointer to Base. The raw pointer will keep the provenance of the original reference, and thus that will work:

// safety: `base` should be a reference to `Derived`, otherwise this is UB
unsafe fn get_derived_from_base<'a>(base: *const Base) -> &'a Derived {
let ptr = base as *const Derived;
&*ptr
}

fn main() {
let d = Derived {
base: Base {
x: 5
},
y: 10,
};

let base = &d as *const Derived as *const Base;
println!("{:?}", unsafe { &*base });

let derived = unsafe { get_derived_from_base(base) };
println!("{:?}", derived);
}

Note: References should not be involved at all in the process. If you'll reborrow base as a reference of type Base, you will lose the provenance again. This will pass Miri on the playground, but is still undefined behavior per the current rules and will fail Miri with stricter flags (set the environment variable MIRIFLAGS to -Zmiri-tag-raw-pointers before running Miri locally).

Why the address of structure and next is not same?

TL;DR

Your code provokes Undefined Behavior, as already mentioned in Morlacke's Answer. Other than that, it seems that you're having problems on understanding how pointers work. See references for tutorials.


First, From your comments

When you say that there's memory allocated for ip in this case:

int i = 10;
int *ip;
ip = &i;

What happens is:

  1. You declare an int variable called i and assign the value 10 to it. Here, the computer allocates memory for this variable on the stack. Say, at address 0x1000. So now, address 0x1000 has content 10.
  2. Then you declare a pointer called ip, having type int. The computer allocates memory for the pointer. (This is important, see bellow for explanation). Your pointer is at address, say, 0x2000.
  3. When you assign ip = &i, you're assigning the address of variable i to variable ip. Now the value of variable ip (your pointer) is the address of i. ip doesn't hold the value 10 - i does. Think of this assignment as ip = 0x1000 (don't actually write this code).
  4. To get the value 10 using your pointer you'd have to do *ip - this is called dereferencing the pointer. When you do that, the computer will access the contents of the address held by the pointer, in this case, the computer will access the contents on the address of i, which is 10. Think of it as: get the contents of address 0x1000.

Memory looks like this after that snippet of code:

VALUE    :   10    | 0x1000 |
VARIABLE : i | ip |
ADDRESS : 0x1000 | 0x2000 |

Pointers

Pointers are a special type of variable in C. You can think of pointers as typed variables that hold addresses. The space your computer allocates on the stack for pointers depends on your architecture - on 32bit machines, pointers will take 4 bytes; on 64bit machines pointers will take 8 bytes. That's the only memory your computer allocates for your pointers (enough room to store an address).

However, pointers hold memory addresses, so you can make it point to some block of memory... Like memory blocks returned from malloc.


So, with this in mind, lets see your code:

NODE *hi;   
printf("\nbefore malloc\n");
printf("\naddress of node is: %p",hi);
printf("\naddress of next is: %p",hi->next);
  1. Declare a pointer to NODE called hi. Lets imagine this variable hi has address 0x1000, and the contents of that address are arbitrary - you didn't initialize it, so it can be anything from zeroes to a ThunderCat.
  2. Then, when you print hi in your printf you're printing the contents of that address 0x1000... But you don't know what's in there... It could be anything.
  3. Then you dereference the hi variable. You tell the computer: access the contents of the ThunderCat and print the value of variable next. Now, I don't know if ThunderCats have variables inside of them, nor if they like to be accessed... so this is Undefined Behavior. And it's bad!

To fix that:

NODE *hi = malloc(sizeof NODE);
printf("&hi: %p\n", &hi);
printf(" hi: %p\n", hi);

Now you have a memory block of the size of your structure to hold some data. However, you still didn't initialize it, so accessing the contents of it is still undefined behavior.

To initialize it, you may do:

hi->id = 10;
hi->next = hi;

And now you may print anything you want. See this:

#include <stdio.h>
#include <stdlib.h>

struct node {
int id;
struct node *next;
};

typedef struct node NODE;

int main(void)
{
NODE *hi = malloc(sizeof(NODE));

if (!hi) return 0;

hi->id = 10;
hi->next = hi;

printf("Address of hi (&hi) : %p\n", &hi);
printf("Contents of hi : %p\n", hi);
printf("Address of next(&next): %p\n", &(hi->next));
printf("Contents of next : %p\n", hi->next);
printf("Address of id : %p\n", &(hi->id));
printf("Contents of id : %d\n", hi->id);

free(hi);

return 0;
}

And the output:

$ ./draft
Address of hi (&hi) : 0x7fffc463cb78
Contents of hi : 0x125b010
Address of next(&next): 0x125b018
Contents of next : 0x125b010
Address of id : 0x125b010
Contents of id : 10

The address of variable hi is one, and the address to which it points to is another. There are several things to notice on this output:

  1. hi is on the stack. The block to which it points is on the heap.
  2. The address of id is the same as the memory block (that's because it's the first element of the structure).
  3. The address of next is 8 bytes from id, when it should be only 4(after all ints are only 4 bytes long) - this is due to memory alignment.
  4. The contents of next is the same block pointed by hi.
  5. The amount of memory "alloced" for the hi pointer itself is 8 bytes, as I'm working on a 64bit. That's all the room it has and needs.
  6. Always free after a malloc. Avoid memory leaks
  7. Never write code like this for other purposes than learning.

Note: When I say "memory alloced for the pointer" I mean the space the computer separates for it on the stack when the declaration happens after the Stack Frame setup.


References

  • SO: How Undefined is Undefined Behavior
  • SO: Do I cast the result of malloc
  • SO: What and where are the stack and heap?
  • Pointer Basics
  • Pointer Arithmetic
  • C - Memory Management
  • Memory: Stack vs Heap
  • Memory Management
  • The Lost Art of C Strucutre Packing will tell you about structures, alignment, packing, etc...


Related Topics



Leave a reply



Submit