2016-10-10 4 views
0

В build_uart_frame() я вызываю calcFCS(), который вычисляет XOR всех байтов в элементах структуры (len, cmd0, cmd1 и data).passign struct struct to function и struct padding in c programming

Я не думаю, что структура заполнена, поэтому вызовет calcFCS() вопрос? Может кто-нибудь объяснить, в чем проблема в отношении прокладки структуры, поскольку я не понимаю ее роли здесь, а во-вторых, как я могу сделать эту операцию правильно?

Спасибо

typedef struct uart_frame { 
    uint8_t sof;     /* 1 byte */ 
    uint8_t len;     /* 1 bytes */ 
    uint8_t cmd0;     /* 1 byte */ 
    uint8_t cmd1; 
    char data[11];   /* 0 -250 byte */ 
    unsigned char fcs;    /* 1 byte */      
} uart_frame_t; 

//------------------------------------------------------------------------- 

// Global uart frame 
    uart_frame_t rdata; 

//------------------------------------------------------------------------- 
    unsigned char calcFCS(unsigned char *pMsg, unsigned char len) { 

    unsigned char result = 0; 
    while(len--) { 
    result ^= *pMsg++; 
    } 

    return(result); 
} 

//------------------------------------------------------------------------- 

// Worker code to populate the frame 

int build_uart_frame() { 

uart_frame_t *rd = &rdata; //pointer variable 'rd' of type uart_frame  

// common header codes 
rd->sof = 0xFE; 
rd->len = 11; 
rd->cmd0 = 0x22; 
rd->cmd0 = 0x05; 
snprintf(rd->data, sizeof(rd->data), "%s", "Hello World"); 
rd->fcs = calcFCS((unsigned char *)rd, sizeof(uart_frame_t) - 1); //issue with struct padding 
return 0; 
} 
+0

'unsigned char len' ->' size_t len' – LPs

ответ

1

Учитывая вашу очень конкретный пример, то маловероятно, что заполнение будет проблемой, так как все типы данных байт. Заполнение в основном является проблемой, когда вы используете более крупные типы данных, потому что они обычно не выделяются по неверным адресам.

Однако это не гарантия: компилятор мог бы в теории решить заменить char на int, если он думает, что получит более быстрый код. Он может вставлять любое количество прокладок в любом месте структуры, за исключением самого верхнего.

Именно поэтому структуры не подходят для описания карт памяти или протоколов данных. Вам нужно будет убедиться, что нет прокладки и желательно сделать это с возможностью переноски. Лучший способ обеспечить это стандартный C во время компиляции утверждает:

_Static_assert(sizeof(uart_frame_t) == offsetof(uart_frame_t, fcs)+sizeof(unsigned char), 
       "Padding detected"); 

Здесь размер всей структуры проверяются на байтовой позицию последнего элемента структуры + размера этого члена. Если они одинаковы, не было прокладки.

Теперь, конечно, это только предотвращает компиляцию и неправильное использование вашего кода, оно не решает проблему. К сожалению, нет портативного способа блокировки отступов. #pragma pack(1) является общим, но нестандартным. __attribute__((packed)) - другая команда для этого.

Обеспечение того, чтобы упаковка в данной системе, в которой скомпилирован код, не является достаточной.

Кроме того, некоторые из более экзотических систем (MIPS, SPARC и т. Д.) Даже не поддерживают неверные чтения, а это означает, что смещенный доступ будет означать не только медленный код, но и ошибку ошибки шины во время выполнения.


Единственный способ безопасно обеспечить максимальную портативность кода с использованием структур, чтобы написать сериализации/десериализации подпрограммы, которые вручную копий каждого члена в/из исходного массива байт:

void uart_serialize (const uart_frame_t* frame, uint8_t* raw) 
{ 
    raw[0] = frame->sof; 
    raw[1] = frame->len; 
    ... 
    memcpy(&raw[4], frame->data, 11); 
    ... 
} 

недостатком таких методов является то, что они, очевидно, добавляют некоторое время выполнения, поэтому я бы использовал их только для кода, который, как мне известно, нужно портировать на всевозможные системы.