c - Initializing, constructing and converting struct to byte array causes misalignment -
i trying design data structure (i have made shorter save space here think idea) used byte level communication:
/* packet.h */ #define cm_header_size 3 #define cm_data_size 16 #define cm_footer_size 3 #define cm_packet_size (cm_header_size + cm_data_size + cm_footer_size) // + other definitions typedef struct cm_header{ uint8_t packetstart; //start indicator 0x5b [ uint8_t deviceid; //id of device sending uint8_t packettype; } cm_header; typedef struct cm_footer { uint16_t datacrc; //crc of 'data' part of cm_packet uint8_t packetend; //should 0x5d or ] } cm_footer; //here trying conver few u8[4] tp u32 (4*u32 = 16 byte, hence data size) typedef struct cm_data { union { struct{ uint8_t value_0_0:2; uint8_t value_0_1:2; uint8_t value_0_2:2; uint8_t value_0_3:2; }; uint32_t value_0; }; //same thing value_1, 2 , 3 } cm_data; typedef struct cm_packet { cm_header header; cm_data data; cm_footer footer; } cm_packet; typedef struct cm_inittypedef{ uint8_t deviceid; cm_packet packet; } cm_inittypedef; typedef struct cm_appendresult{ uint8_t result; uint8_t reason; } cm_appendresult; extern cm_inittypedef cmhandler;
the goal here make reliable structure transmitting data on usb interface. @ end cm_packet
should converted uint8_t
array , given data transmit register of mcu (stm32).
in main.c
file try init structure other stuff related packet:
/* main.c */ uint8_t packet[cm_packet_size]; int main(void) { //use extern defined in packet.h init struct cmhandler.deviceid = 0x01; //assign device id cm_init(&cmhandler); //construct handler //rest of stuff while(1) { cm_getpacket(&cmhandler, (uint8_t*)packet); cdc_transmit_fs(&packet, cm_packet_size); } }
and here implementation of packet.h
screws bad. added packet[cm_packet_size]
watch being generated randomly. pure luck can see in array of values interested in! 1% of time!
/* packet.c */ cm_inittypedef cmhandler; void cm_init(cm_inittypedef *cm_initer) { cmhandler.deviceid = cm_initer->deviceid; static cm_packet cmpacket; cmpacket.header.deviceid = cm_initer->deviceid; cmpacket.header.packetstart = cm_start; cmpacket.footer.packetend = cm_end; cm_initer->packet = cmpacket; } cm_appendresult cm_appenddata(cm_inittypedef *handler, uint8_t identifier, uint8_t *data){ cm_appendresult result; switch(identifier){ case cm_value_0: handler->packet.data.value_0_0 = data[0]; handler->packet.data.value_0_1 = data[1]; handler->packet.data.value_0_2 = data[2]; handler->packet.data.value_0_3 = data[3]; break; //also cases cm_value_0, 1 , 2 //to build cm_data sturct of cm_packet default: result.result = cm_append_failure; result.reason = cm_append_case_error; return result; break; } result.result = cm_append_success; result.reason = 0x00; return result; } void cm_getpacket(cm_inittypedef *handler, uint8_t *packet){ //copy whole struct in given buffer , later send usb host memcpy(packet, &handler->packet, sizeof(cm_packet_size)); }
so, problem code gives me 99% of time random stuff. never has cm_start
start indicator of packet value want to. of time has cm_end
byte correctly! got confused , cant find out reason. being working on embedded platform hard debugg kind of lost here...
if transfer data (different) architecture, not pass structure blob. way hell: endianess, alignment, padding bytes, etc. can (and will) cause trouble.
better serialize struct in conforming way, possily using interpreted control stream not have write every field out manually. (but still use standard functions generate stream).
some areas of potential or trouble:
cm_footer
: second field might start @ 32 or 64 bit boundary, preceeding field followed padding. also, end of struct padded @ least 1 bytes on 32 bit architecture allow proper alignment if used in array (the compiler not care if need this). might 8 byte aligned.cm_header
: here (not guaranteed) 1 uint8_t 4*2 bits ordering not standardized. field followed 3 unused bytes required uint32_t interprettion of union.- how guarantee same endianess (for >uint8_t: high byte first or low byte first?) host , target?
- in general, structs/unions need not have same layout host , target. if same compiler used, abis may differ, etc. if same cpu, there might other system constraints. also, cpus, different abis (application binary interface) exist.
Comments
Post a Comment