I'm beginner and I have a problem. I have this structure:
typedef struct {
char data[26];
int index;
Placa_baza pb; // char nume_placa[10], int index_placa;
} PC;
And a structure vector:
static PC computers[5] = { ... };
I need to have a vector of type uint8_t pc[5*sizeof(computers)] instead of the structure vector.
Is it well declared that way? :
uint8_t pc[5*sizeof(computers)]
How can I convert (cast) vector uint8_t pc[5*sizeof(computers)] to PC?
To use the uint8_t pointer to address the structure, how should it be written?
Thank you in advance.
Your pc array, which could serve as a backup for the PC data is too large: it is sufficient to define it as:
uint8_t pc[sizeof(computers)];
Or possibly:
uint8_t pc[5 * sizeof(PC)];
You can then copy computers to pc with:
memcpy(pc, computers, sizeof pc);
You could also use a pointer to access the pc array as an array of PC:
PC *p = (PC *)pc; // Don't do this!
Note however that this has undefined behavior as the byte array pc might not be properly aligned to access members of the PC structure, especially the index member and using such a pointer is a violation of the strict aliasing rule. It would be much better to define pc as PC pc[5]; and access this array via a uint8_t pointer of so required.
WARNING: Below program is just demonstration purpose, it may not behave same way with all compilers/systems. You can use it to test your compilers or systems behavior and modify accordingly.
In the below program am copying the contents from the structure computers to unit8_t.
as you can see its not easy and not portable, because we need to extract the data as per the boundaries of memory, allocated for variables.
#include <stdio.h>
#include <stdint.h>
#include <string.h>
typedef struct
{
char nume_placa[10];
int index_placa;
}Placa_baza;
typedef struct {
char data[26];
int index;
Placa_baza pb;
}PC;
int main()
{
printf("sizeof(int) = %zu\n", sizeof(int));
printf("sizeof(Placa_baza) = %zu\n", sizeof(Placa_baza));
printf("sizeof(PC) = %zu\n", sizeof(PC));
static PC computers[3] = { {"data1",1,"comp1", 0}, {"data2",2,"comp2", 1}, {"data3",3,"comp3", 2} };
printf("sizeof(computers) = %zu\n\n", sizeof(computers));
for(int i =0; i<3; i++)
printf("data = %s, index =%d, pb.nume_placa =%s, pb.index_placa =%d\n",
computers[i].data,
computers[i].index,
computers[i].pb.nume_placa,
computers[i].pb.index_placa
);
uint8_t uint8_t_pc[sizeof(computers)] = {0};
// for copying the contents from pc (uint8_t), used same variable names as that of structures
/* typedef struct { */
char data[26];
int index;
/* Placa_baza pb;
} PC; */
/* typedef struct
{ */
char nume_placa[10];
int index_placa;
/* }Placa_baza;
*/
printf("\n sizeof(uint8_t_pc) = %zu\n", sizeof(uint8_t_pc));
memcpy(uint8_t_pc,computers,sizeof(computers));
int count = 0;
uint8_t* temp = uint8_t_pc;
printf("\n **From uint8_t memory ***\n");
while(count < 3) {
memcpy(data, temp, 26);
// since there is a padding of 2 bytes , so extract from 28
memcpy(&index, temp+28, 4);
memcpy(nume_placa, temp+32, 10);
//again there is a padding of 2 bytes
memcpy(&index_placa, temp+44, 4);
printf("data = %s, index = %d, nume_placa =%s , index_placa =%d\n", data, index, nume_placa, index_placa);
temp = temp+sizeof(computers[0]);
count++;
}
return 0;
}
Output:
sizeof(int) = 4
sizeof(Placa_baza) = 16
sizeof(PC) = 48
sizeof(computers) = 144
data = data1, index =1, pb.nume_placa =comp1, pb.index_placa =0
data = data2, index =2, pb.nume_placa =comp2, pb.index_placa =1
data = data3, index =3, pb.nume_placa =comp3, pb.index_placa =2
sizeof(uint8_t_pc) = 144
**From uint8_t memory ***
data = data1, index = 1, nume_placa =comp1 , index_placa =0
data = data2, index = 2, nume_placa =comp2 , index_placa =1
data = data3, index = 3, nume_placa =comp3 , index_placa =2
online source
Update:
Indeed we can use offsetof to get the offset of any member of the structure, so the statements inside while can also be replaced by below statments.
memcpy(data, temp+offsetof(PC, data), sizeof(computers[count].data));
memcpy(&index, temp+offsetof(PC, index), sizeof index);
memcpy(nume_placa, temp+offsetof(PC, pb.nume_placa), sizeof computers[count].pb.nume_placa);
memcpy(&index_placa, temp+offsetof(PC, pb.index_placa), sizeof index_placa);
Related
I have a function that initializes a struct that contains nested structs and arrays.
While initializing the struct I have multiple calls to calloc.
Refer to code bellow:
typedef struct
{
int length;
uint8_t *buffer;
} buffer_a;
typedef struct
{
int length;
uint8_t *buffer;
int *second_buffer_size;
uint8_t **second_buffer;
} buffer_b;
typedef struct
{
int max_length;
buffer_a *buffer_in;
buffer_b *buffer_out;
} state_struct;
state_struct *init(int size, int elements) {
size_t struct_size = sizeof(state_struct);
state_struct *s = (state_struct*) calloc(struct_size, struct_size);
log("Building state with length %d", size);
s->max_length = size;
size_t buffer_in_size = s->max_length * sizeof(buffer_a);
s->buffer_in = (buffer_a*) calloc(buffer_in_size, buffer_in_size);
size_t buffer_out_size = s->max_length * sizeof(buffer_b);
s->buffer_out = (buffer_b*) calloc(buffer_out_size, buffer_out_size);
log("Allocated memory for both buffers structs");
for (int i = 0; i < s->max_length; ++i) {
size_t buf_size = elements * sizeof(uint8_t);
s->buffer_in[i].buffer = (uint8_t*) calloc(buf_size, buf_size);
s->buffer_in[i].length = -1;
log(s, "Allocated memory for in buffer");
s->buffer_out[i].buffer = (uint8_t*) calloc(buf_size, buf_size);
s->buffer_out[i].length = -1;
log(s, "Allocated memory for out buffer");
size_t inner_size = elements * elements * sizeof(uint8_t);
size_t inner_second_buffer_size = elements * sizeof(int);
s->buffer_out[i].second_buffer = (uint8_t**) calloc(inner_size, inner_size);
s->buffer_out[i].second_buffer_size = (int*) calloc(inner_second_buffer_size, inner_second_buffer_size);
log(s, "Allocated memory for inner buffer");
}
return s;
}
Logs just before the for loop are printed but the program crashes and the first log statement inside the loop does not get printed out.
Why is this happening?
So this may not be an answer to your question, but here goes:
When I ran this code (on Ubuntu, gcc 7.4), and replaced all the log functions with printf, it finished succesfuly. I suspect the problem might be in the way you use the log function. You specify that it works up until the first log call inside the loop. You didn't specify what the log function does, or whether it is a function or just a macro wrapper for printf, but you call it in a different manner inside the loop - the first parameter is *state_struct rather than a format string.
Also, the way you call calloc seems to be semantically incorrect. The first parameter should be the number of blocks of second parameter size you want to allocate (presumably 1 in this case)
Trying to write a C snippet to store and retrieve an array of structure pointers. I have copied my snippet bellow.
What I am trying to do here-
method Xos_get_cb_info_from_handle() should return the pointer to
the base address of the structure localclient.exit_cb. Which seem to
work.
After getting this base address, I would like to index into the array.
As part of this exercise temp1 should store the address of the 0'th index (first element), temp2 should store the address of 1st index (second element).
My observations are: (look at the output at the end of the code)
I get the base address correct here in temp1 which is 0x40300c
However, the next element (index 1) should be 0x403010. This is in fact 0x40301c. It seems like its being incremented by the size of the structure.
What is going on here? As per pointer arithmetic shouldn't C be increment this by size of structure (but by size of the pointer.)
Can anyone help me shade some light on this scenario? Any code change suggestions are welcomed. Thanks!
#include <stdio.h>
#define X_PROCESS_DUMP_CB_MAX 3
typedef struct {
void* cb_func; /* pointer to callback function */
unsigned cb_arg; /* not interpreted by the framework*/
} X_cb_data_t;
typedef struct err_cb_t{
X_cb_data_t Xos_cb;
unsigned short priority;
struct err_cb_t *next;
}Xos_exit_cb_t;
struct Xos_local_client {
int x; //just placeholder
Xos_exit_cb_t *exit_cb[X_PROCESS_DUMP_CB_MAX];
int y; //just placeholder
};
/*static global to this file, init this in main before accessing it*/
static struct Xos_local_client localclient;
int Xos_get_cb_info_from_handle(int client_handle, Xos_exit_cb_t** cb_head)
{
*cb_head = (Xos_exit_cb_t *)&localclient.exit_cb[0];
return 0;
}
int main()
{
int i = 0;
/*init localclient here*/
localclient.x =1;
localclient.y =2;
for(i =0; i< X_PROCESS_DUMP_CB_MAX; i++)
{
Xos_exit_cb_t *exit_cb_p = (Xos_exit_cb_t *)malloc(sizeof(Xos_exit_cb_t));
localclient.exit_cb[i] = exit_cb_p;
printf("&exit_cb_p: %p exit_cb_p: %p\n", (unsigned int)&localclient.exit_cb[i],(unsigned int)exit_cb_p);
}
/*Test code that fails*/
Xos_exit_cb_t** exit_cb_head; /*Pointer to pointer of exit_cb*/
Xos_exit_cb_t **temp1;
Xos_exit_cb_t **temp2;
if (!Xos_get_cb_info_from_handle(3, exit_cb_head)) {
temp1 = &(*exit_cb_head)[0];
temp2 = &(*exit_cb_head)[1];
printf("temp1: %p, temp2: %p\n", temp1, temp2);
}
return 0;
}
/*Output*/
&exit_cb_p: 0x40300c exit_cb_p: 0xd18628
&exit_cb_p: 0x403010 exit_cb_p: 0xd426c0
&exit_cb_p: 0x403014 exit_cb_p: 0xd426d8
exit_cb_head: 0x40300c, temp1: 0x40300c, temp2: 0x40301c
In your for loop
for(i =0; i< X_PROCESS_DUMP_CB_MAX; i++)
{
Xos_exit_cb_t *exit_cb_p = (Xos_exit_cb_t *)malloc(sizeof(Xos_exit_cb_t));
localclient.exit_cb[i] = exit_cb_p;
printf("&exit_cb_p: %p exit_cb_p: %p\n", (unsigned int)&localclient.exit_cb[i],(unsigned int)exit_cb_p);
}
you are iterating the pointer array. So you see an increment according to pointer arithmetic (increment by pointer size)
Now assuming your code here missed the copy paste mentioned in the comment by #reichhart i.e.
Xos_exit_cb_t** exit_cb_head = &(localclient.exit_cb[0]);
temp1 & temp2 (of type Xos_exit_cb_t *) are actual addresses in memory where structure is allocated. Hence, base address of adjacent elements will be separated by size of structure.
Hope that helps.
My question is like this
below is the structure which i have to populate and send it through socket
struct Mystruct
{
int numofarray1elements;
array1[50];
int numofarray2elements;
array2[25];
};
Here size of 1 array1 member is 1024 bytes i.e total size of array1 = 50*1024 = 51200 bytes
size of 1 member of array2 is say 500 so total size of array2 = 12500 bytes
whenever i use send api of socket(unix domain socket) i have to send 51200+12500 +4+4 = 63708 bytes
Problem is i have to send entire size of structure even if i have very less
numofarray1elements, and numofarray2elements
this leads to performance issue
where in almost cases my original data can be less than 10kb but i end up sending 63k everytime
i cannot keep dynamic arrays as its socket message
i have already otimized my data strutures , array1 must have max 50 elements
array2 must have max 25 elements.
now is there any way that i can send exact data which i have populated?
please provide some method if any
Thanks
Actually the way for doing it is to have messages of variable length. One of the methods is to use a single array with undefined size as the last element of the struct. Depending on the types of the messages it could be represented by messages or by bytes, e.g.
struct Mystruct
{
int numofarray1elements;
int numofarray2elements;
char array[];
};
The size of your struct can be calculated as the size of static fields plus sizes needed for actual payload as this:
int packetSize = (sizeof(struct Mystruct) + n1 * sizeof(el1) + n2 * sizeof(el2));
now you can use it to allocate the struct and send the packet in a single operation.
struct Mystruct *packet = malloc(packetSize);
// assign packet fields
...
write(fd, packet, packetSize);
Here is a simple example which emulates a version of write/read. It will work if writer and reader have the same endian order. It also assumes that the packet size is sent separately an is known to the reader.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
struct Mystruct {
int numofarray1elements;
int numofarray2elements;
char payload[];
};
struct Element1 {
int len;
char name[30];
};
struct Element2 {
char name[20];
int len;
};
// reader emulation
void readData(int packetSize, char *dataIn) {
union {
char data[packetSize];
struct Mystruct packet;
} dataUnion;
int i;
struct Element1 *e1 = NULL;
struct Element2 *e2 = NULL;
memcpy(dataUnion.data, dataIn, packetSize);
printf("Read data e1 size is %d, e2 size is %d\n",
dataUnion.packet.numofarray1elements, dataUnion.packet.numofarray2elements);
e1 = malloc(sizeof(struct Element1) * dataUnion.packet.numofarray1elements);
e2 = malloc(sizeof(struct Element2) * dataUnion.packet.numofarray2elements);
memcpy(e1, dataUnion.packet.payload, sizeof(struct Element1) * dataUnion.packet.numofarray1elements);
memcpy(e2, dataUnion.packet.payload + sizeof(struct Element1) * dataUnion.packet.numofarray1elements,
sizeof(struct Element2) * dataUnion.packet.numofarray2elements);
for (i = 0; i < dataUnion.packet.numofarray1elements; i++) {
printf("e1[%d].len = %d, name = %s\n", i, e1[i].len, e1[i].name);
}
for (i = 0; i < dataUnion.packet.numofarray2elements; i++) {
printf("e2[%d].len = %d, name = %s\n", i, e2[i].len, e2[i].name);
}
}
void main() {
struct Element1 e1[4];
struct Element2 e2[8];
int i;
int packetSize;
struct Mystruct *packet = NULL;
for (i = 0; i < 4; i++) {
sprintf(e1[i].name, "e1:%d", i);
e1[i].len = i;
}
for (i = 0; i < 8; i++) {
sprintf(e2[i].name, "e2:%d", i);
e2[i].len = i;
}
// emulated write data
packetSize = (sizeof(struct Mystruct) + sizeof(e1) + sizeof(e2));
packet = malloc(packetSize);
packet->numofarray1elements = 4;
packet->numofarray2elements = 8;
memcpy(packet->payload, &e1, sizeof(e1));
memcpy(packet->payload + sizeof e1, &e2, sizeof(e2));
// here you do write data, e.g. write(socFd, packet, packetSize);
// emulate read data
readData(packetSize, (char*)packet);
}
Instead of using structures, use TLV mechanism. So for your solution: you can use Type , , Count of Type, Length , Value.
Define types which is known at both receiver and sender side
Define your message structure as
Type taking 2 bytes, Count-of-type taking 2 or 4 bytes , Length taking 4 bytes and Value.
This is extensible as you can add any number of types in future as long as the type is known at both side. At receiver side if type is not known, they can ignore that TLV.
You should not send structs over network protocols (or store them in files, etc). You need to serialize them.
But to solve your problem, simply change your send code:
//this is what your code looks like, I assume:
write(sockFd, myStructVariable, sizeof(struct MyStruct));
to:
//be aware of writev(2) if you want to send these in one system call at once, or copy them into one buffer
write(sockFd, myStructVariable.numofarray1elements, sizeof(int));
write(sockFd, myStructVariable.array1, sizeof(MyArray1) * myStructVariable.numofarray1elements);
write(sockFd, myStructVariable.numofarray2elements, sizeof(int));
write(sockFd, myStructVariable.array2, sizeof(MyArray2) * myStructVariable.numofarray2elements);
or something similar
Then change your receive code:
read(sockFd, myStructVariable.numofarray1elements, sizeof(int));
read(sockFd, myStructVariable.array1, sizeof(MyArray1) * myStructVariable.numofarray1elements);
read(sockFd, myStructVariable.numofarray2elements, sizeof(int));
read(sockFd, myStructVariable.array2, sizeof(MyArray2) * myStructVariable.numofarray2elements);
of course, you could also leave the array and counts defined locally and send those instead. Make sure you check for errors, short reads, etc
Take a look at flatbuffers as well, this lets you write structures that come with serialization functions
I need to serialise a struct and I am trying to do this using memcpy. But it is not working. I can tell by looking at the byte stream - I see garbage characters. Why?
Also I get runtime error:
Run-Time Check Failure #2 - Stack around the variable 'addresses' was corrupted.
What is happening and how can I fix this?
I am using #pragma pack(push, 1) which I thought would mean there would be no padding of the structs.
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#pragma pack(push, 1) /* padding has to be disabled for casting to struct to work at other end */
typedef struct {
uint8_t start_char;
uint8_t msg_type;
uint8_t length;
} MSG_HEADER;
typedef struct {
uint8_t denomination[6];
uint8_t path;
uint8_t min_level;
uint16_t max_level;
uint16_t weight;
uint8_t address;
} CONFIG_DATA;
typedef struct {
MSG_HEADER header;
uint8_t clear_type;
CONFIG_DATA config_data[12];
uint8_t system_algorithm;
uint8_t max_transaction;
} MSG_CONFIGURATION;
#pragma pack(pop) /* only affect this file */
typedef struct {
unsigned char data[256];
size_t length;
int msg_type;
} TCHU_MESSAGE;
enum DRM_MESSAGE_TYPE {
CONFIG, CLEAR_COUNT, DISPENSE, CANCEL_TRANSACTION };
void TestCopy()
{
MSG_CONFIGURATION config;
config.clear_type = 0;
config.system_algorithm = 0;
config.max_transaction = 17;
const int NumItems = 12;
const uint16_t maxLevel = 300;
static const char* denoms[] = { "GB005A","GB005B","GB010A","GB010B",
"GB020A","GB050A","GB050B","GB100A",
"GB100B","GB200A", "EU100A", "EU100B" };
const uint8_t addresses[] = { 0, 0, 5, 5, 0, 7, 7, 8, 8, 9, 0, 0 };
const uint8_t sorting_paths[] = { 5, 5, 4, 4, 5, 2, 2, 1, 1, 3, 0, 0 };
for(int i = 0; i < NumItems; ++i) {
memcpy(config.config_data[i].denomination, denoms[i], 6);
config.config_data[i].address = addresses[i];
config.config_data[i].path = sorting_paths[i];
config.config_data[i].min_level = 3;
config.config_data[i].max_level = maxLevel;
config.config_data[i].weight = 1000;
}
config.header.start_char = 1;
config.header.msg_type = 2;
config.header.length = sizeof(MSG_CONFIGURATION);
TCHU_MESSAGE tchu_msg = {0};
// why does the memcpy not work? How can I get it to work?
memcpy(tchu_msg.data, &config+sizeof(MSG_HEADER), sizeof(MSG_CONFIGURATION) - sizeof(MSG_HEADER));
printf("sizeof(MSG_HEADER) = %u\n", sizeof(MSG_HEADER));
printf("sizeof(MSG_CONFIGURATION) = %u\n", sizeof(MSG_CONFIGURATION));
// get garbage in copyconfig
MSG_CONFIGURATION copyconfig;
memcpy(©config+sizeof(MSG_HEADER), tchu_msg.data, sizeof(MSG_CONFIGURATION) - sizeof(MSG_HEADER));
if(copyconfig.header.start_char != config.header.start_char)
{
// we get to here
printf("mismatch between original and copy\n");
}
}
int main() {
TestCopy();
// I also get Run-Time Check Failure #2 - Stack around the variable 'addresses' was corrupted.
// when program ends
}
My compiler instantly told me what was wrong:
warning: '__builtin___memcpy_chk' will always overflow destination buffer [-Wbuiltin-memcpy-chk-size]
memcpy(©config+sizeof(MSG_HEADER), tchu_msg.data, sizeof(MSG_CONFIGURATION) - sizeof(MSG_HEADER));
Why is that? Well, let's look at the destination:
©config + sizeof(MSG_HEADER)
That means "Take the address of copyconfig, treat it as an array, and take the Nth object where N is sizeof(MSG_HEADER). I think you thought it would add N bytes, but it actually adds N instances of MSG_CONFIGURATION. Instead, use this:
©config.header + 1
That is, "Take the address of copyconfig.header and go to just beyond it."
You could equally do this:
(char*)©config + sizeof(MSG_HEADER)
Because the size of one char is one byte. Or, since your struct is packed:
©config.clear_type
Because that's the address of the first byte you actually want to copy into.
For more details, read: Pointer Arithmetic .
I'm working in the arduino environment. I have a struct defined as follows. The struct will ultimately be encrypted and sent wirelessly over a radio link layer. It's 32bytes long.
struct SENSORTYPE{
int sensor1:8;
int sensor2:8;
int sensor3:8;
int sensor4:8;
};
struct SENSOR{
float sensor1;
float sensor2;
float sensor3;
float sensor4;
};
struct HEADER{
byte type;
short id;
short to;
short from;
byte version;
long _buff;
SENSORTYPE sensortype;
SENSOR sensor;
};
HEADER header;
I have an XTEA encryption/decryption routine that's defined as follows and is verified to work. It operates on two 32bit blocks at at time.
void xteaEncrypt( unsigned long v[2])
void xteaDecrypt(unsigned long v[2])
What I'm trying to do is run header through xteaEncrypt. I'm getting tripped up on converting my struct to the two 32bit numbers. The following is what I have so far.
#define BLOCK_SIZE 8
header.type = 1; //test value
header._buff = 1; //test value
byte data[BLOCK_SIZE]; //8 byte buffer to encrypt/decrypt
byte buff[32]; //32 byte buffer to put encrypted/decrypted data into
for (uint32_t i = 0; i < 4; i++){ //4 times (4 * 8 = 32)
memcpy(data, &header+(i*BLOCK_SIZE), BLOCK_SIZE); //copy 8 bytes from header struct into data
xteaEncrypt((uint32_t*)data); //encrypt data
memcpy(&buff+(i*8), data, BLOCK_SIZE); //put encrypted data into the new buffer
}
memcpy(&header, &buff, sizeof(header)); //copy into original header for convenience
//now decrypt it back
for (uint32_t i = 0; i < 4; i++){
memcpy(data, &header+(i*BLOCK_SIZE), BLOCK_SIZE);
xteaDecrypt((uint32_t*)data);
memcpy(&buff+(i*8), data, BLOCK_SIZE);
}
memcpy(&header, &buff, sizeof(header));
After encryption header.type = 0xee and header._buff = C0010000. After decryption, header.type = 1 and _buff still = C0010000 so it would seem there is an error in my memcpy'ing but I can't find it. Any help would be greatly appreciated. This one has been particularly hard to debug for me. If I'm going about this completely wrong let me know and point me in the right direction.
You're getting tripped up by pointer arithmetic. Consider the snippet &header+(i*BLOCK_SIZE). What you evidently expect to happen is that you'll get some address, let's call it addr, and then add some small number to it to calculate a new address, i.e.
finalAddress = addr + (i * 8);
But because &header is a pointer to a struct HEADER, the actual calculation the compiler does is
finalAddress = addr + (sizeof(struct HEADER) * i * 8);
The result is an address that's well beyond the end of the header for any i greater than 0. The same thing is happening with &buff+(i*8), since &buff is a pointer to 32 bytes.
To solve the problem, I recommend using intermediate variables that are char *, e.g.
char *headAddress = (char *)&header;
char *buffAddress = (char *)&buff;
for (uint32_t i = 0; i < 4; i++)
{
memcpy(data, headAddress+(i*BLOCK_SIZE), BLOCK_SIZE);
xteaEncrypt((uint32_t*)data);
memcpy(&buffAddress+(i*BLOCK_SIZE), data, BLOCK_SIZE);
}