Cast 0 to struct pointer - c

So, I have this code here:
struct mystruct {
char a;
union {
char a[8];
char b[16];
} u;
};
void fuu(void)
{
struct mystruct s;
printf("%ld %ld\n", sizeof(s), &((struct mystruct *)0)->u.b);
}
The snippet that confuses me is:
&((struct mystruct *)0)->u.b
As far as I can understand it, firstly pointer to struct is casted to lvalue int of 0(what?)
Then, u.b is taken out of this pointer(which should be a pointer to the start of char array b)
Then address of this pointer is taken and printed to the screen.
The most confusing moment of all this is cast to 0.
Can someone explain in detail what is happening in this snippet?

Let's break it down a bit. Assume that we have a variable x that is a pointer to a mystruct:
struct mystruct *x;
And replace that in the expression in question:
&(x->u.b)
This takes the address of the member u.b in the struct that x points to. We can guess that this address should be slightly higher than x itself, because u is not the first member in the struct.
Then, add the fact that x is zero:
struct mystruct *x = (struct mystruct *)0;
Then, the value of the expression above will be slightly higher than 0. Or in other words, it will be the offset of u.b within the memory layout of the struct.
In fact, at least on my machine it's 1, because the only member in the struct before u is char a, which takes up 1 byte.*
Another way to do this is to use the offsetof macro defined in stddef.h:
#include <stddef.h>
...
printf("%ld %ld\n", sizeof(s), offsetof(struct mystruct, u.b));
It has the same effect, but it might be easier to understand what the code is trying to do.
* And none of the members of the union have greater alignment requirements. Try changing either of the members of the union from char to int - what happens?
The offset is printed as 4 instead of 1, because an int needs to be stored in an address divisible by 4. So the struct will contain one byte for char a, three unused bytes for alignment, and then the union.

Related

I have memory address of an struct store in int variable. Can I dereference the struct using this int value in C?

I have address of an struct store in int variable. Can I dereference the struct??
say: int x = 3432234; // memory address of struct
now I want to access the some struct from it.
I have been suggest these steps.
store the address in an int variable
cast that int to a struct pointer
then dereference it
But don't know how to apply.
If you have a struct foo, the easy way is to not use an int x but make the type a pointer-to-struct foo, struct foo *x. One can use the arrow operator to access members from a valid pointer directly.
#include <stdio.h>
struct foo { int a, b; };
int main(void) {
struct foo foo = { 1, 2 };
struct foo *x = &foo;
printf("%d, %d\n", x->a, x->b);
}
Sometimes, hardware requirements complicate this, but this is the simple solution.
It is very common to use structs this way in mare metal environments as hardware registers are often memory mapped.
typedef struct
{
volatile uint32_t reg1;
const volatile uint32_t reg2;
}PERIPH1__t;
#define PERIPH1ADDRESS 0x56664550UL
/* OR */
uintptr_t PERIPH1ADDRESS = 0x56664550UL;
#define PERIPH1 ((PERIPH1__t *)PERIPH1ADDRESS)
/* somewhere in the code */
PERIPH1 -> reg1 = 34;
uint32_t reg2val = PERIPH1 -> reg2;
if you want to store the address in the integer variable, the best type will be uintptr_t which is guaranteed to accommodate any pointer.
int is signed and on many systems not large enough to store addresses - for example 64 bits systems often have 64 bits addresses and only 32bits integers.

Declaration and definition of union

Why does this code work:
#include<stdio.h>
int main(){
union var{
int a, b, c;
};
printf("%ld", sizeof(union var));
return 0;
}
My doubt is that isn't union var a declaration only, and during declaration no memory is allocated. So why does this code print 4?
It prints 4 because that's how big a union var variable is. The fact that there are no union var variables in your program, is completely irrelevant. If you created one, for example by writing union var myUnionVar;, it would use 4 bytes of memory
You can also do this with structs:
struct list_node {
struct list_node *next;
int key;
int value;
};
// note that sizeof returns a size_t which should be printed with %zu
printf("%zu", sizeof(struct list_node)); // prints 12 or 16, probably
sizeof is an operator that yields the size in bytes of its argument (right-hand-side operand). The operand can either be a type or a variable. Most of the time, the result is a constant that can be evaluated at compile time.
union var is a type, therefore with sizeof(union var) you are asking "what size would occupy a variable if it had the type union var?" The answer is 4 bytes.

What is the sizeof the pointer pointing to a structure variable?

I am trying to print the size of pointers in both the cases. For both the cases I am getting 8 16 as output.
#include <stdio.h>
struct Book
{
char name[10];
int price;
};
int main(void)
{
struct Book a; // Single structure variable
struct Book* ptr; // Pointer of Structure type
ptr = &a;
struct Book b[10]; // Array of structure variables
struct Book* p; // Pointer of Structure type
p = &b;
printf("%ld %ld\n",sizeof(ptr),sizeof(*ptr));
printf("%ld %ld\n",sizeof(p),sizeof(*p));
return 0;
}
First of all, sizeof operator yields a type size_t, you must use %zu to print that.
Then, usually in any architecture, the size of a pointer is always constant, irrespective of the type they point to. In other words, a pointer needs to hold a memory location, and for any normal architecture, the address (of a memory location) has a fixed size. So, the size of any pointer, is same.
Is this what you want, in the second case:
printf("%zu %zu\n", sizeof(p1), sizeof(*p1));
// Output
8 160
Okay! Let's start from the beginning.
As Sourav Ghosh stated in his answer, "A pointer needs to hold a memory location, and for any normal architecture, the address (of a memory location) has a fixed size. So, the size of any pointer is the same.", regardless of its data type which it points to.
Now coming to your problem, consider and try to understand this modified version of your program:
#include <stdio.h>
struct Book
{
char name[10];
int price;
};
int main(void)
{
struct Book b[10]; // Array of structure variables
struct Book* p; // Pointer to type struct Book
struct Book (*p1)[10]; // Pointer to type struct Book[], which is array of type struct Book
p = b; // same as p = &b[0] but not as p = &b
p1 = &b; // this is how assignment of a pointer to array is done
printf("%zu %zu\n", sizeof(struct Book*), sizeof(struct Book));
printf("%zu %zu\n",sizeof(p),sizeof(*p));
printf("%zu %zu\n",sizeof(p1),sizeof(*p1));
return 0;
}
Output:
// perhaps on your PC
8 16
8 16
8 160
// on my PC
4 16
4 16
4 160
You see in the output that sizeof(struct Book), sizeof(p), and sizeof(p1), all are the same. Thus, size of any type of pointer is the same.
But when you are printing the size of the struct Book, i.e. you are asking the compiler, "tell me how much bytes of memory this struct Book contains",
for the first two cases (sizeof(struct Book) or sizeof(*p)), it is 16 and for the last case it is 160 which is size of 10 variables of type struct Book.
And if you're wondering why 16 as the size of a variable of type stuct Book, that's because of the 2 padding bytes in between the char and int member.
Read this SO question about padding and packing in structures.

Cast void pointer to struct and move it given size

I got a binary file that contains 3 different structs which I'm suppose to read to my program. After I have read the first struct I store its size, and then I'm suppose to convert my void pointer + the first structs length to a struct ip_hdr * (which is the second struct) and then read all it's values.
But the problems is I don't understand how you move a void pointer. I have understood that the void pointers don't have the same arithmetic rules as like a int pointer.
I want to do something like this:
ptr = (struct ip_hdr *)ptr) + (ethRes));
But that doesn't work instead I get following error message:
Expression must be a pointer to a complete object type
Here is my code:
#pragma warning(disable: 4996)
#include <stdio.h>
#include <stdlib.h>
#include "framehdr.h"
#include <crtdbg.h>
int main()
{
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
FILE *fileOpen = fopen("C:\\Users\\Viktor\\source\\repos\\Laboration_3\\Laboration_3\\TCPdump", "rb");
//Pointers and variables
struct ethernet_hdr eth;
struct ethernet_hdr *ethPtr;
struct ip_hdr ip;
struct ip_hdr *ipPtr;
struct tcp_hdr tcp;
struct tcp_hdr *tcpPtr;
if (fileOpen == NULL)
{
printf("Error\n");
}
else
{
printf("Success\n");
}
char ethrr[10];
fscanf(fileOpen, "%s", ethrr);
int length = atoi(ethrr);
printf("Nr: %d\n", length);
void *ptr;
ptr = (void *)malloc(length);
fread(ptr, sizeof(eth), 1, fileOpen);
int ethRes = sizeof(((struct ethernet_hdr*)ptr)->dhost) +
sizeof(((struct ethernet_hdr*)ptr)->shost) +
sizeof(((struct ethernet_hdr*)ptr)->type);
printf("%d\n", ethRes);
printf("ptr1: %d\n", &ptr);
system("pause");
fclose(fileOpen);
return 0;
}
I now it's broken but I'm not done with it. Just need help with the pointers for now.
This should work, assuming the structure is compatible with whatever is in the file (in general saving structs "raw" to disk is a bad idea, the exact layout of a struct in memory is compiler-dependent and not stable enough to use as a file format):
const struct ip_hdr * const ip = (struct ip_hdr *) ((struct ethernet_hdr *) ptr + 1);
This adds "1" to a pointer of type ethernet_hdr, which will advance the actual pointer value by whatever size the Ethernet header structure has. The result is then cast to struct ip_hdr *.
I think this is what you wanted to do. You can do it by adding bytes to a char *, but what's the point?
You can't add directly to the void pointer, since pointer arithmetic is always in units of whatever is pointed at, and void has no size.
Here's an example of moving along an array of structures using a pointer to void.
The compiler doesn't know the type of object pointed to by a void* pointer.
So you have two choices. One is to convert it to a pointer to the 'correct' type and then add the number of elements you want to move. The other is to add the number of bytes you want to an unsigned char* (or similar).
The action happens on the lines marked [1] and [2] below.
#include <stdio.h>
typedef struct {
int payload;
double other;
} thingy;
int main(void) {
thingy athingy[2];//An array of two thingys.
void* voidptr=athingy; //a pointer to first thingy.
thingy* nextthingy=((unsigned char*)voidptr)+sizeof(thingy); //[A] next thingy points to second element of array.
thingy* altnext=((thingy*)voidptr)+1; //[B] Points to the same thing!
printf("voidptr==%p %zu\n",voidptr,sizeof(thingy));
printf("nextthingy==%p\n",nextthingy);
printf("altthingy==%p\n",altnext);
if(nextthingy==altnext){
printf("Same\n");
}else{
printf("Not same (oh dear)\n");
}
return 0;
}
Typical output:
voidptr==0x7ffd6909d660 4
nextthingy==0x7ffd6909d664
altthingy==0x7ffd6909d664
Same
The actual values may vary.
Caveat
If I understand the question, the requirement is to move through a number of different structs read together.
That may be problematic because of alignment. It's beyond the scope of this question to go into detail but C may place or require padding between members or objects of different type to ensure they are aligned on the architecture. It's very common for example for 4 byte integers to lie on memory addresses that numerically divide by 4. That simplifies hardware and improves performance.
It's not clear from the fragment provided that the objects read in will be aligned and further copying of data and shuffling may be required.
That may have been taken into account but that can't be seen from the information provided.
What may help is the often overlooked offsetof(,) macro defined in stddef.h.
That returns the offset of a member within a type (taking internal padding into consideration). For example there is in general no guarantee (above) that:
voidptr+sizeof(payload)==((unsigned char*)voidptr)+offsetof(thingy,other)

Casting struct * to int * to be able to write into first field

I've recently found this page:
Making PyObject_HEAD conform to standard C
and I'm curious about this paragraph:
Standard C has one specific exception to its aliasing rules precisely designed to support the case of Python: a value of a struct type may also be accessed through a pointer to the first field. E.g. if a struct starts with an int , the struct * may also be cast to an int * , allowing to write int values into the first field.
So I wrote this code to check with my compilers:
struct with_int {
int a;
char b;
};
int main(void)
{
struct with_int *i = malloc(sizeof(struct with_int));
i->a = 5;
((int *)&i)->a = 8;
}
but I'm getting error: request for member 'a' in something not a struct or union.
Did I get the above paragraph right? If no, what am I doing wrong?
Also, if someone knows where C standard is referring to this rule, please point it out here. Thanks.
Your interpretation1 is correct, but the code isn't.
The pointer i already points to the object, and thus to the first element, so you only need to cast it to the correct type:
int* n = ( int* )i;
then you simply dereference it:
*n = 345;
Or in one step:
*( int* )i = 345;
1 (Quoted from: ISO:IEC 9899:201X 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.
You have a few issues, but this works for me:
#include <malloc.h>
#include <stdio.h>
struct with_int {
int a;
char b;
};
int main(void)
{
struct with_int *i = (struct with_int *)malloc(sizeof(struct with_int));
i->a = 5;
*(int *)i = 8;
printf("%d\n", i->a);
}
Output is:
8
Like other answers have pointed out, I think you meant:
// Interpret (struct with_int *) as (int *), then
// dereference it to assign the value 8.
*((int *) i) = 8;
and not:
((int *) &i)->a = 8;
However, none of the answers explain specifically why that error makes sense.
Let me explain what ((int *) &i)->a means:
i is a variable that holds an address to a (struct with_int). &i is the address on main() function's stack space. This means &i is an address, that contains an address to a (struct with_int). In other words, &i is a pointer to a pointer to (struct with_int). Then the cast (int *) of this would tell the compiler to interpret this stack address as an int pointer, that is, address of an int. Finally, with that ->a, you are asking the compiler to fetch the struct member a from this int pointer and then assign the value 8 to it. It doesn't make sense to fetch a struct member from an int pointer. Hence, you get error: request for member 'a' in something not a struct or union.
Hope this helps.

Resources