2016-10-10 11 views
0

build_uart_frame()で、structメンバー(len、cmd0、cmd1およびdata)のすべてのバイトのXORを計算するcalcFCS()を呼び出します。passign関数への構造体ポインタとプログラミング中のstruct padding

structがパッドされているとは思わないので、calcFCS()と呼びますか?私はここでその役割を理解していないので、誰かがstruct paddingとの関係で何が問題であるのかを説明することができましたか、第二にこの操作を正しく行うことができますか?

はあなたの非常に具体的な例を考えると

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

が、すべてのデータ型はバイトであるため、パディングは、問題になることはほとんどありませんありがとうございます。大容量のデータ型を使用すると、パディングは主に問題になります。通常、整列していないアドレスには配置しないでください。

しかし、これは保証ではありません。コンパイラは理論的にはcharintに置き換えることを決めました。一番上を除いて、構造体のどこにでもパディングを自由に挿入できます。

これは、structがメモリマップまたはデータプロトコルを記述するのに適していない理由です。パッディングが存在しないことを保証しなければなりません。できればそうすることができます。これは、標準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); 
    ... 
} 

そのようなメソッドの欠点は、明示的に実行時間が追加されていることです。そのため、私はすべての種類の異なるシステムに移植する必要があることがわかっているコードに対してのみ使用します。

関連する問題