Pointer manipulation to access elements in a struct - c

Given the below simple code, where you have process_payload is given a pointer to the payload portion of the packet, how do you access the header portion? Ideally the caller should simply give a pointer to full packet from beginning, but there are cases where you don't have the beginning of the message and need to work backwards to get to the header info. I guess this question becomes a understanding of walking through the memory layout of a struct.
The header computes to 8 bytes with sizeof operation. I assume Visual C++ compiler added 3 bytes padding to header.
The difference between pptr and pptr->payload is decimal 80 (not sure why this value??) when doing ptr arith (pptr->payload - pptr). Setting ptr = (struct Packet*)(payload - 80) works but seems more a hack. I don't quite understand why subtracting sizeof(struct header) doesn't work.
Thanks for any help you can give.
struct Header
{
unsigned char id;
unsigned int size;
};
struct Packet
{
struct Header header;
unsigned char* payload;
};
void process_payload(unsigned char* payload);
int main()
{
struct Packet* pptr = (struct Packet*)malloc(sizeof(struct Packet));
pptr->payload = (unsigned char*)malloc(sizeof(unsigned char)*10);
process_payload(pptr->payload);
return 1;
}
// Function needs to work backwards to get to header info.
void process_payload(unsigned char* payload)
{
// If ptr is correctly setup, it will be able to access all the fields
// visible in struct Packet and not simply payload part.
struct Packet* ptr;
// This does not work when intuitively it should?
ptr = (struct Packet*)(payload - sizeof(struct Header));
}

It's because in main you allocate two pointers, and pass the second pointer to the process_payload function. The two pointers are not related.
There are two ways of solving this problem, where both include a single allocation.
The first solution is to used so called flexible arrays, where you have an array member last in the structure without any size:
struct Packet
{
struct Header header;
unsigned char payload[];
};
To use it you make one allocation, with the size of the structure plus the size of the payload:
struct Packet *pptr = malloc(sizeof(struct Packet) + 10);
Now pptr->payload is handled like a normal pointer pointing to 10 unsigned characters.
Another solution, which is a mix of your current solution and the solution with flexible arrays, is to make one allocation and make the payload pointer to point to the correct place in the single allocated memory block:
struct Packet
{
struct Header header;
unsigned char *payload;
};
// ...
struct Packet *pptr = malloc(sizeof(struct Packet) + 10);
pptr->payload = (unsigned char *) ((char *) pptr + sizeof(struct Packet);
Note that in this case, to get the Packet structure from the payload pointer, you have to use sizeof(Packet) instead of only sizeof(Header).
Two things to note about the code above:
I don't cast the result of malloc
sizeof(char) (and also the size of unsigned char) is specified to always be one, so no need for sizeof

Related

Type casting struct to short/int for saving value on adress

I would like to know, if its possible to cast struct to short but only 2 bites of its adress and save value in there. I personally dont even know if its possible just wanna get any ideas how to do that.
In my project i link void adress of char to struct and then doing something similar like malloc but without using malloc.. making somthing like function malloc.
My struct and its pointer:
typedef struct mem_list {
int size;
struct mem_list *next;
struct mem_list *prev;
}mem_list;
mem_list *start;
my function memory init:
void memory_init(void *ptr, unsigned int size){
mem_list *temp;
temp = (mem_list*)ptr;
if(size <= sizeof(mem_list)){
temp->size = 0;
printf("Failed\n");
return;
}
else
{
temp->size = size - sizeof(mem_list);
temp->next = NULL;
*((unsigned short*)(&temp + size - sizeof(unsigned short))) = 0;
start = temp;
printf("Inicialized was %d bits\n",size-sizeof(mem_list));
return;
}
}
My main:
int main() {
char region[100];
memory_init(region, 60);
//char* pointer = memory_alloc(20);
//printf("adresa %d\n", pointer);
return 0;
}
My problem is in function memory init in this part of code:
*((unsigned short*)(&temp + size - sizeof(unsigned short))) = 0;
What i want to do is to move to end of my inicialized memory and save there short typed zero for showing me later where is end of my memory. And also would like to ask how can i acces that value later? I know there maybe are mistakes in my code. Woul be happy if you point me where and give me some ideas how to do that. thank you :)
(&temp + size - sizeof(unsigned short))): &temp is the address of the pointer to your mem_list, so &temp + xxx is the address of somewhere in the stack :-(
The address of the last byte of your mem_list object is (char*)temp + size.
To be cleaner you could define your
typedef struct mem_list {
int size;
struct mem_list *next;
struct mem_list *prev;
unsigned short body[]
} mem_list_t ;
Then:
blen = (size + sizeof(unsigned short) - 1) / sizeof(unsigned short) ;
temp->body[blen] = 0 ;
writes 0 to the last unsigned short of the body of the mem_list_t.
Note that this assumes that ptr points to an object which has been allocated with asize bytes:
asize = offsetof(mem_list_t, body[blen+1]) ;
with blen calculated as above. (And ptr needs to be aligned as required for mem_list_t, of course.)
It is not clear whether you can reuse a char buffer to create objects of other types in it(*), but you should at least care about alignment. Some processors require non char types to be correctly aligned, for example that:
the address of an int16_t shall be even
the address of an int32_t or larger shall be a multiple of 4
And even if some other processors do not enforce this rule, accessing mis-aligned data often adds a significant overhead. That is the reason for padding in structs.
So without more precautions, this line:
*((unsigned short*)(&temp + size - sizeof(unsigned short))) = 0;
could break because if size is odd, you are trying to write an unsigned short at an odd address.
(*) For more details, you can read that other post from mine, specialy the comments on my own answer
if its possible to cast struct to short but only 2 bites of its adress and save value in there
No, it isn't possible. *((unsigned short*)(&temp...) invokes undefined behavior. It is a so-called "strict aliasing violation" and can also lead to misalignment issues depending on system. What is the strict aliasing rule?
The rule of thumb is: never wildly cast between completely different pointer types. You need a lot of detailed knowledge about C in order to so in a safe manner.
You can do "type punning" either by using a union between the struct and a unsigned short though. Please note that endianess is an issue to consider when doing so.
Other than that, you can safely memcpy the contents of a struct into an allocated unsigned short or vice versa. memcpy is excempt from pointer aliasing rules and will handle alignment safely.

Type casting struct pointer

I'm trying to get into Socket programming and came across an article at https://www.tenouk.com/Module43a.html I'm having difficulty understanding as how a char array is cast into struct pointer
char buffer[PCKT_LEN];
struct ipheader *ip = (struct ipheader *) buffer;
//some code here
ip->iph_ihl = 5;
ip->iph_ver = 4;
ip->iph_tos = 16;
As per my understanding, pointer ip will now hold the address of buffer and values for members of struct ipheader will now be stored in buffer. Please help understanding the same. If I'm right, then how would we be able to print values stored in buffer?
You understanding is correct. The pointer *ip will point to buffer. char buffer[PCKT_LEN] is an array of size sizeof(char) * PCKT_LEN. Since a char is usually 1 byte long it is just a chunk of memory of PCKT_LEN bytes. PCKT_LEN is defined to be 8192
The amount of bytes needed to store a struct ipheader is much less than this. Try int a = sizeof(ipheader) and use a debugger to see the value assigned to a. For me it is 24 bytes, but it could be slightly different for you. This means that buffer can hold much more data than the struct ipheader needs. I haven't looked to deeply into the code, and I don't know much about socket programming. But one use for this could be to augment buffer with additional data outside of the struct. Since you know struct ipheader takes up sizeof(ipheader) bytes you will have sizeof(char)*8192 - sizeof(ipheader) left to augment the array.
Edit:
Upun further inspection, this is kinda what is happening:
struct ipheader *ip = (struct ipheader *) buffer;
struct udpheader *udp = (struct udpheader *) (buffer + sizeof(struct ipheader));
It tries to store the ip header at the beginning of the buffer, then it augments that same buffer with an udp header. By using buffer + sizeof(struct ipheader)
it makes sure that it stores the udp header after ipheader by offsetting buffer by sizeof(struct ipheader) bytes. Basically struct ipheader *ip points to the beginning of the buffer and struct udpheader *udp points to buffer + sizeof(struct ipheader). I hope this makes sense. Obviously there is still a lot of space left over in buffer so you could potentially augment it even further.
how a char array is cast into struct pointer
You can't do that safely. The code invokes undefined behavior:
char buffer[PCKT_LEN];
struct ipheader *ip = (struct ipheader *) buffer;
//some code here
ip->iph_ihl = 5;
ip->iph_ver = 4;
ip->iph_tos = 16;
That code violates the strict aliasing rule. That basically means memory that isn't a certain type of object can't be treated as being that type of object, with the exception that any non-char object can be treated as an array of char.
That's not what's happening in the posted code. In the posted code, a char array is being treated as if it were a struct ipheader.
The memory is not a struct ipheader - it's an array of char - so the code violates strict aliasing.
The casting from char * to struct ipheader * can also result in an improperly aligned object and violate 6.3.2.3 Pointers, paragraph 7:
A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined. ...
Code such as you've found here is unfortunately all too common as the x86-based machines that are the most common platform widely used by programmers are very forgiving of misaligned accesses, so such code tends to "work".
See Structure assignment in Linux fails in ARM but succeeds in x86 for an example of a platform where it doesn't work.

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)

Cast struct to array?

I'm currently learning C and I have trouble understanding the following code:
struct dns_header
{
unsigned char ra : 1;
unsigned char z : 1;
unsigned char ad : 1;
unsigned char cd : 1;
unsigned char rcode : 4;
unsigned short q_count : 16;
};
int main(void)
{
struct dns_header *ptr;
unsigned char buffer[256];
ptr = (struct dns_header *) &buffer;
ptr->ra = 0;
ptr->z = 0;
ptr->ad = 0;
ptr->cd = 0;
ptr->rcode = 0;
ptr->q_count = htons(1);
}
The line I don't understand is ptr = (struct dns_header *) &buffer;
Can anyone explain this in detail?
Your buffer is simply a contiguous array of raw bytes. They have no semantic from the buffer point of view: you cannot do something like buffer->ra = 1.
However, from a struct dns_header * point of view those bytes would become meaningful. What you are doing with ptr = (struct dns_header *) &buffer; is mapping your pointer to your data.
ptr will now points on the beginning of your array of data. It means that when you write a value (ptr->ra = 0), you are actually modifying byte 0 from buffer.
You are casting the view of a struct dns_header pointer of your buffer array.
The buffer is just serving as an area of memory -- that it's an array of characters is unimportant to this code; it could be an array of any other type, as long as it were the correct size.
The struct defines how you're using that memory -- as a bitfield, it presents that with extreme specificity.
That said, presumably you're sending this structure out over the network -- the code that does the network IO probably expects to be passed a buffer that's in the form of a character array, because that's intrinsically the sanest option -- network IO being done in terms of sending bytes.
Suppose you want to allocate space for the struct so you could
ptr = malloc(sizeof(struct dns_header));
which will return a pointer to the allocated memory,
ptr = (struct dns_header *) &buffer;
is almost the same, except that in this case it's allocated in the stack, and it's not necessary to take the address of the array, it can be
ptr = (struct dns_header *) &buffer[0];
or just
ptr = (struct dns_header *) buffer;
there is no problem in that though, because the addresses will be the same.
The line I don't understand is ptr = (struct dns_header *) &buffer;
You take the address of the array and pretend like it is a pointer to a dns_header. It is basically raw memory access, which is unsafe, but OK if you know what you are doing. Doing so will grant you access to write a dns_header in the beginning of the array.
Ideally, it should be an array of dns_headers not a byte array. You have to be cautious about the fact that dns_header contains bit fields, the implementation of which is not enforced by the standard, it is entirely up to the compiler vendors. Although bit field implementations are fairly "sane", there is no guarantee, so the size of a byte array might actually be mismatched with your intent.
Adding to the other answers posted:
This code is illegal since ANSI C. ptr->q_count = htons(1); violates the strict aliasing rule.
It is only permitted to use an unsigned short lvalue (i.e. the expression ptr->q_count) to access memory that either has no declared type (e.g. malloc'd space), or has declared type of short or unsigned short or compatible.
To use this code as-is, you should pass -fno-strict-aliasing to gcc or clang. Other compilers may or may not have a similar flag.
An improved version of the same code (which also has some forwards-compatibility to the structure size changing) is:
struct dns_header d = { 0 };
d.q_count = htons(1);
unsigned char *buffer = (unsigned char *)&d;
This is legal because the strict aliasing rule permits unsigned char to alias anything.
Note that buffer is currently unused in this code. If your code is actually a smaller snippet of larger code then buffer may have to be defined differently. In any case, it could be in a union with d.
A struct directly references a contiguous block of memory and each field within a struct is located at a certain fixed offset from the start. Variables can then be accessed via a struct pointer or by the struct declared name which returns the same address.
Here we declare a packed struct which references a contiguous block of memory:
#pragma pack(push, 1)
struct my_struct
{
unsigned char b0;
unsigned char b1;
unsigned char b2;
unsigned char b3;
unsigned char b4;
};
#pragma pack(pop)
Pointers can then be used to refer to the struct by its address. See this example:
int main(void)
{
struct my_struct *ptr;
unsigned char buffer[5];
ptr = (struct my_struct *) buffer;
ptr->b0 = 'h';
ptr->b1 = 'e';
ptr->b2 = 'l';
ptr->b3 = 'l';
ptr->b4 = 'o';
for (int i = 0; i < 5; i++)
{
putchar(buffer[i]); // Print "hello"
}
return 0;
}
Here we explicitly map 1:1 the struct contiguous block of memory to the contiguous block of memory pointed by buffer (using the address to the first element).
An array address and the name of the address are numerically identical but have different types. These two lines are thus equivalent:
ptr = (struct my_struct *) buffer;
ptr = (struct my_struct *) &buffer;
This is usually not a problem if we use the address as is and cast it appropriately. Dereferencing an array address of type pointer to array-of-type yields the same pointer but with a different type array-of-type.
Although it might seem convenient to manipulate memory in this fashion, it is strongly discouraged as the resulting code becomes painfully difficult to understand. If you really have no choice, I suggest using an union to specify that the struct is to be used in a particular manner.

Access data after a header structure

I am doing some network programming, and I use some struct to describe my frame header like that:
struct my_frame_header {
uint16_t field1;
uint16_t field2;
};
And so, when I have a buffer frame I can do something like that:
uint8_t buffer[BUFFER_SIZE];
struct my_frame_header *frame_header = (struct my_frame_header *)buffer;
my_read(buffer, BUFFER_SIZE);
I can now access to the header field like that:
ntohl(frame_header->field1);
Now, my question is: What is the most elegant way to access the data after the structure? (i.e. to get a pointer at the beginning of the data part)
Well, if I understood your question correctly, you can do something like
uint8_t * data = (uint8_t *)buffer + sizeof (struct my_frame)
then, data will be a pointer to the next uint8_t element after the header.
uint8_t buffer[BUFFER_SIZE];
struct my_frame_header *frame_header = (struct my_frame_header *)buffer;
This is wrong, the base address of buffer can be unaligned for my_frame_header.
Take look to Memory access and alignment
On the other hand:
The block that malloc gives you is guaranteed to be aligned so that it
can hold any type of data.
Then, you can use malloc in order to skip this problem:
uint8_t *buffer = malloc(BUFFER_SIZE);

Resources