C Converting a struct to an array of bytes and back again - c

I want to convert a struct to an array of bytes, and back again taking the bytes and converting/casting them to the struct.
here's some hypothetical code:
let's assume we have a struct foo
struct foo
{
int x;
float y;
} typedef foo;
assuming that we have already allocated some memory of 1000 bytes, i want to be able to put the bytes that the struct above represents into my already allocated 1000 bytes.

How about memcpy(ptrToAllocedMemory, &structOnStack, sizeof(structOnStack));?

Too convert a struct to an array of bytes ...
Simple assigned via a union. The members of foo will be copied with the assignment, perhaps any padding too. #Eric Postpischil
struct foo {
int x;
float y;
} typedef foo;
foo data_as_foo;
union x_foo {
foo bar;
unsigned char array_o_bytes[sizeof foo];
} x;
x.bar = data_as_foo;
// Do something with x.array_o_bytes
for (unsigned i = 0; i < sizeof x.array_o_bytes; i++) {
printf("%2X ", x.array_o_bytes[i]);
}
An assignment is not even needed.
union x_foo = { .bar = data_as_foo );
What is important about return trip for bytes without alignment to foo is to use memcpy().
foo bytes_to_foo(const unsigned char *data) {
foo y;
memcpy(&y, data, sizeof y);
return y;
}
If the bytes are aligned, as a member of union x_foo, than an assignment is sufficient.
union x_foo data_as_bytes;
// data_as_bytes.array_o_bytes populated somehow
foo data_as_foo = x_foo data_as_bytes.bar;

You can simply make a pointer to the address, cast it and handle it from there.
A full code snipping demonstrating what you asked:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct foo
{
int x;
float y;
} typedef foo;
int main () {
char *mem = malloc(1000); // preallocated memory as requested
foo bar; // initial struct
bar.x = 10; // initialize struct
bar.y = 12;
char *ptr =(char*)(&bar); //cast a char ptr to bar's address
memcpy(mem, ptr, sizeof(foo)); // copy it over
foo *result = (foo *)(mem); // cast the memory to a pointer to foo
printf("%d, %f\n", result->x,result->y); // and it works!
return 0;
}
If you wanted to cast the pointer and copy it in one line, you could also do
memcpy(mem,(char*)(&bar), sizeof(foo));
For the same effect.

All variables and struct in C are stored in memory, and memory is already array of bytes.
So, in contrast to Java or C#, you do not need to do any additional transformation:
// to get struct's bytes just convert to pointer
struct foo tmp;
unsigned char* byte_array = (unsigned char*)&tmp;
// from bytes to struct
_Alignas(struct foo) unsigned char byte_array2[sizeof(struct foo)];
struct foo* tmp2 = (struct foo*)byte_array2;
as people are pointing in comments - conversion from array to struct could lead to UB on some platforms, so its better to avoid it unless you allocated properly aligned block

Related

Referencing a struct member with pointer arithmetic

I've got a struct definition,
struct liste{
unsigned int size;
unsigned int capacity;
char* data;
};
and an instance,
struct liste lst = {3, 4, "hi"};
and what I'm trying to do is get the data member without directly calling lst.data. So far I've been able get a pointer, dataC ;
char* dataC = (char *) ((char *)&lst + 2 * sizeof(unsigned int));
whereby printing dataC and &lst.data as pointers gives the same output. I thought dereferencing dataC and casting the result to a char * would yield a pointer identical lst.data but I get a segfault.
Is there something I'm missing??
According to your code, dataC does not store the address of the data "hi", but the address of the pointer of lst.data. You can see the code below. dataC is the address of lst.data. *dataC is the address of the string "hi", the same as lst.data.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include<stdint.h>
struct liste{
unsigned int size;
unsigned int capacity;
char *data;
};
int main()
{
struct liste lst = {3, 4,"hi"};
char **dataC = (char **) ((char *)&lst + 2 * sizeof(unsigned int));
printf("datac = %s\n",(*dataC));
}
Your code is neither portable nor rugged, because there might be struct padding inside the struct. If you need to do something like you attempt here, you should be using the offsetof macro, which is used to get the byte offset of a member inside a struct. Example:
#include <stdio.h>
#include <stddef.h> // offsetof
struct liste{
unsigned int size;
unsigned int capacity;
char* data;
};
int main (void)
{
struct liste lst = {3, 4, "hi"};
char** ptrptr = (char**) ((char*)&lst + offsetof(struct liste, data)) ;
puts(*ptrptr);
}
Notably the (char*)&list part has nothing to do with the data we are looking for being of char type. This is simply a way of iterating through a larger data type byte by byte, which C allows if we use character pointers. We end up with a character pointer pointing at the location of (the pointer) data inside the struct. By casting the result to char**, we make it clear that whatever we are pointing at is a char*.
Similarly, we could get the capacity member like this:
unsigned int** pp_cap = (unsigned int**) ((char*)&lst + offsetof(struct liste, capacity)) ;
printf("%d\n", *pp_cap);

How to assign value to multiple member a structure at once

Let's assume that we have a struct that has 4x 1-byte members.
I want to use Xyz as a memory address and cast it as a 32bit pointer then I will assign values to it.
By this, I would able to set all the byte members at once.
This is just an example for my question, char, int, or set to 256 is just arbitrary examples.
#include <stdio.h>
struct temp{
char abc;
char def;
char ghk;
char lmn;
}xyz;
int main()
{
xyz = (struct temp){11,22,33,44};
printf("Byte1 %d\r\n",xyz.abc);
printf("Byte2 %d\r\n",xyz.def);
printf("Byte3 %d\r\n",xyz.ghk);
printf("Byte4 %d\r\n",xyz.lmn);
*((unsigned int*)xyz) = 256;
printf("Byte1 %d\r\n",xyz.abc);
printf("Byte2 %d\r\n",xyz.def);
printf("Byte3 %d\r\n",xyz.ghk);
printf("Byte4 %d\r\n",xyz.lmn);
return 0;
}
Here I prepare a similar approach for the array which is working as expected ;
#include <stdio.h>
char mem[4];
int main()
{
mem[0] = 49;
mem[1] = 50;
mem[2] = 51;
mem[3] = 52;
printf("Byte1 %d\r\n",mem[0]);
printf("Byte2 %d\r\n",mem[1]);
printf("Byte3 %d\r\n",mem[2]);
printf("Byte4 %d\r\n",mem[3]);
*(int*)mem = 256;
printf("Byte1 %d\r\n",mem[0]);
printf("Byte2 %d\r\n",mem[1]);
printf("Byte3 %d\r\n",mem[2]);
printf("Byte4 %d\r\n",mem[3]);
return 0;
}
How can I do the same thing that I did by an array by using struct?
This:
*((unsigned int*)xyz) = 256;
Is a strict aliasing violation. This means you can't take a pointer to one type, cast it to another type, dereference the casted pointer, and expect things to work. The only exception is casting to a pointer to char * to read the individual bytes of some other type.
What you can do however is use a union. It is permitted to write to one member of a union and read from another to reinterpret the bytes as a different type. For example:
union u {
int i;
struct {
char c1;
char c2;
char c3;
char c4;
} s;
};
...
union u u1;
u1.i = 256;
printf("byte1=%02x\n", u1.c1);
printf("byte2=%02x\n", u1.c2);
printf("byte3=%02x\n", u1.c3);
printf("byte4=%02x\n", u1.c4);

Creating, returning, and casting a struct with a char pointer in C

I'm pretty bad at remembering C rules with structs. Basically, I have a struct like this:
typedef struct {
char* ptr;
int size;
} Xalloc_struct;
Where the char* ptr will only be one character max.
In my program, I have to allocate and free memory to a fake disk (declared globally as char disk[100];) using my own functions:
char disk[100];
void disk_init() {
for(int i = 0; i < 100; ++i) {
disk[i] = memory[i] = 0;
}
}
struct Xalloc_struct* Xalloc(int size) {
// error checking
// ...
// run an algorithm to get a char* ptr back to a part of the global disk
// array, where index i is the index where content at disk[i] starts
char* ptr = &disk[i];
struct Xalloc_struct *ret = malloc(sizeof(struct Xalloc_struct));
ret->size = size;
ret->ptr = malloc(sizeof(char));
ret->ptr = ptr;
return ret;
}
int Xfree(void* ptr) {
struct Xalloc_struct* p = (struct Xalloc_struct*) ptr;
int size = p->size;
int index = *(p->ptr);
// .. more stuff here that uses the index of where p->ptr points to
free(p->ptr);
free(p);
return 0;
}
int main() {
disk_init();
struct Xalloc_struct* x = Xalloc(5);
Xfree(x);
return 0;
}
When this compiles I get quite a few errors:
error: invalid application of ‘sizeof’ to incomplete type ‘struct Xalloc_struct’
struct Xalloc_struct *ret = malloc(sizeof(struct Xalloc_struct));
^
error: dereferencing pointer to incomplete type
ret->size = size;
^
error: dereferencing pointer to incomplete type
free(x->ptr);
^
error: dereferencing pointer to incomplete type
int size = cast_ptr->size;
^
error: dereferencing pointer to incomplete type
int free_ptr = *(cast_ptr->ptr);
^
So, how should I be allocating and deallocating these structs? And how can I modify / edit what they contain?
First problem is Xalloc_struct is a type, not the name of a struct. You declared that type with this:
typedef struct {
char* ptr;
int size;
} Xalloc_struct;
typedef is of the form typedef <type name or struct definition> <name of the type>. So you declared the type Xalloc_struct to be struct { char *ptr; int size; }.
That means you use it like any other type name: Xalloc_struct somevar = ...;.
Had you declared the struct with a name...
struct Xalloc_struct {
char* ptr;
int size;
};
Then it would be struct Xalloc_struct somevar = ...; as you have.
The rule of thumb when allocating memory for an array (and a char * is an array of characters) is you allocate sizeof(type) * number_of_items. Character arrays are terminated with a null byte, so for them you need one more character.
Xalloc_struct *ret = malloc(sizeof(Xalloc_struct));
ret->ptr = malloc(sizeof(char) * num_characters+1);
But if you're only storing one character, there's no need for an array of characters. Just store one character.
typedef struct {
char letter;
int size;
} Xalloc_struct;
Xalloc_struct *ret = malloc(sizeof(Xalloc_struct));
ret->letter = 'q'; /* or whatever */
But what I think you're really doing is storing a pointer to a spot in the disk array. In that case, you don't malloc at all. You just store the pointer like any other pointer.
typedef struct {
char* ptr;
int size;
} Xalloc_struct;
Xalloc_struct *ret = malloc(sizeof(Xalloc_struct));
ret->ptr = &disk[i];
Then you can read that character with ret->ptr[0].
Since you didn't allocate ret->ptr do not free it! That will cause a crash because disk is in stack memory and cannot be free'd. If it were in heap memory (ie. malloc) it would probably also crash because it would try to free in the middle of an allocated block.
void Xalloc_destroy(Xalloc_struct *xa) {
free(xa);
}
Here's how I'd do it.
#include <stdio.h>
#include <stdlib.h>
char disk[100] = {0};
typedef struct {
char *ptr;
int idx;
} Disk_Handle_T;
static Disk_Handle_T* Disk_Handle_New(char *disk, int idx) {
Disk_Handle_T *dh = malloc(sizeof(Disk_Handle_T));
dh->idx = idx;
dh->ptr = &disk[idx];
return dh;
}
static void Disk_Handle_Destroy( Disk_Handle_T *dh ) {
free(dh);
}
int main() {
Disk_Handle_T *dh = Disk_Handle_New(disk, 1);
printf("%c\n", dh->ptr[0]); /* null */
disk[1] = 'c';
printf("%c\n", dh->ptr[0]); /* c */
Disk_Handle_Destroy(dh);
}
What you are attempting to accomplish is a bit bewildering, but from a syntax standpoint, your primary problems are treating a typedef as if it were a formal struct declaration, not providing index information to your Xalloc function, and allocating ret->ptr where you already have a pointer and storage in disk.
First, an aside, when you are specifying a pointer, the dereference operator '*' goes with the variable, not with the type. e.g.
Xalloc_struct *Xalloc (...)
not
Xalloc_struct* Xalloc (...)
Why? To avoid the improper appearance of declaring something with a pointer type, (where there is no pointer type just type) e.g.:
int* a, b, c;
b and c above are most certainly NOT pointer types, but by attaching the '*' to the type it appears as if you are trying to declare variables of int* (which is incorrect).
int *a, b, c;
makes it much more clear you intend to declare a pointer to type int in a and two integers b and c.
Next, in Xfree, you can, but generally do not want to, assign a pointer type as an int (storage size issues, etc.) (e.g. int index = *(p->ptr);) If you need a reference to a pointer, use a pointer. If you want the address of the pointer itself, make sure you are using a type large enough for the pointer size on your hardware.
Why are you allocating storage for ret->ptr = malloc(sizeof(char));? You already have storage in char disk[100]; You get no benefit from the allocation. Just assign the address of the element in disk to ptr (a pointer can hold a pointer without further allocation) You only need to allocate storage for ret->ptr if you intend to use the memory you allocate, such as copying a string or multiple character to the block of memory allocated to ret->ptr. ret->ptr can store the address of an element in data without further allocation. (it's unclear exactly what you intend here)
You are free to use a typedef, in fact it is good practice, but when you specify a typedef as you have, it is not equivalent to, and cannot be used, as a named struct. That is where your incomplete type issue arises.
All in all, it looks like you were trying to do something similar to the following:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char* ptr;
int size;
} Xalloc_struct;
char disk[100] = "";
Xalloc_struct *Xalloc (int size, int i) {
char *ptr = &disk[i];
Xalloc_struct *ret = malloc (sizeof *ret);
ret->size = size;
// ret->ptr = malloc (sizeof *(ret->ptr)); /* you have a pointer */
ret->ptr = ptr;
return ret;
}
int Xfree (void *ptr) {
Xalloc_struct *p = (Xalloc_struct *) ptr;
// int size = p->size; /* unused */
// int index = *(p->ptr); /* what is this ?? */
// .. more stuff here that uses the index of where p->ptr points to
// free (p->ptr);
free (p);
return 0;
}
int main (void) {
int i = 0;
Xalloc_struct *x = Xalloc (5, i++);
Xfree(x);
return 0;
}
Look at the difference in how the typedef is used and let me know if you have any questions.

Dynamic struct inside of struct

I can't quite figure out how to do this, I've tried this and several variations and some will compile and seemingly work ok but I'll get very random segfaults and it has something to do with the way I'm declaring these structs. All the info in the structs are dynamic. Please let me know the proper way to do this, thank you.
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
char* s2string1;
char* s2string2;
int s2int1;
} struct2;
typedef struct
{
char* s1string1;
char* s1string2;
struct struct2* mystruct;
int int1;
} struct1;
struct struct2* RetS2(char* CopyMe)
{
int* Array = (int*) malloc (sizeof (int) * 5);
Array[0] = strlen (CopyMe);
struct struct2* S2 = (struct struct2*) malloc ( sizeof (struct2) );
S2->s2int1 = Array[0];
return S2;
}
struct struct1* RetS1()
{
struct struct1* S1 = (struct struct1*) malloc ( sizeof (struct1) );
struct struct2* S2 = RetS2();
S1->mystruct = S2;
S1->int1 = S2->S2int1;
return S1;
}
int main()
{
struct struct1 Top = RetS1();
if (Top->mystruct->s2int1 == 10)
// do something
return 0;
}
Your code has multiple issues:
This is the main issue:
RetS2's function definition is
struct struct2* RetS2(char* CopyMe)
which means that it expects a char* as its first argument. But when you call it:
struct struct2* S2 = RetS2();
you don't pass an arguments. This invokes Undefined Behavior.
Here:
int* Array = (int*) malloc (sizeof (int) * 5);
You allocate memory for 5 ints. You use the first element of the array and stops using it. You also forgot the free the allocated memory for Array.
The cast in malloc (and family) is not required in C.
You don't free the malloced memory for S2 and S1.

Setting pointer in struct to an array in C

I am debugging some code and just wanted to make sure that the way I am setting a pointer to an array inside my struct is correct.
Here is an example of what I am trying to do:
typedef struct Foo
{
uint32_t *bar;
} Foo
int main(void)
{
Foo *foo;
uint32_t *bar[20];
foo = (Foo *)malloc(sizeof(Foo));
*bar = malloc(sizeof(uint32_t) * 20);
for(int i = 0; i < 20; i++)
{
bar[i] = (uint32_t*)malloc(sizeof(uint32_t));
}
foo->bar = *bar;
}
The code
uint32_t *bar[20];
declares bar as an array of 20 pointers to uint32_t which is probably not what you intended. Since you allocate the array dynamically with malloc, you should declare bar as a pointer rather than an array:
uint32_t **bar;
You may want to consider doing the memory allocation in a single malloc() rather than the piecewise approach you are using. For instance you might want to consider doing something like the following.
This allocates the memory needed in a single call to malloc() so that only a single call to free() is needed to release the memory. It is faster and tends to make the heap to be less fragmented and easier to manage.
typedef struct
{
uint32_t *bar[1]; // an array of size one that makes array syntax easy
} Foo;
Foo *FooCreateFoo (unsigned int nCount)
{
// create an array of pointers to uint32_t values along with the
// memory area for those uint32_t data values.
Foo *p = malloc (sizeof(uint32_t *) * nCount + sizeof(uint32_t) * nCount);
if (p) {
// we have memory allocated so now initialize the array of pointers
unsigned int iLoop;
uint32_t *pData = p->bar + nCount; // point to past the last array element
for (iLoop = 0; iLoop < nCount; iLoop++) {
// set the pointer value and initialize the data to zero.
*(p->bar[iLoop] = pData++) = 0;
}
}
return p;
}
int main(void)
{
Foo *foo = FooCreateFoo (20);
if (! foo) {
// memory allocation failed so exit out.
return 1;
}
// ... do things with foo by dereferencing the pointers in the array as in
*(foo->bar[1]) += 3; // increment the uint32_t pointed to by a value of 3
free (foo); // we be done with foo so release the memory
}

Resources