【C言語】
memcmpで構造体比較すると穴に落ちる(padding)

memcmpの 落とし穴

warning: padding struct to align ‘i2’

警告:i2′ を整列するため構造体に詰め物した
[-Wpadded]


■境界調整のために穴が開く

構造体のメンバの割り付けはコンパイラ任せなので
各メンバがピッタリ隙間なく割り付けられるとは限りません。
境界調整のために穴が開く場合があり
穴に何が書かれているかは誰もわかりません。

■構造体パディングの例

#include    <stdio.h>
#include    <string.h>
#include    <stdint.h>
struct  hole    {
    uint32_t    i1 ;
    uint8_t     c  ;
    //3byteの穴    
    uint32_t    i2 ;
} g = {
    .i1 = 0x12345678,
    .c  = 0xab,
    .i2 = 0x87654321 
};
//自動変数領域をFFで汚す
//最適化されないよう自動変数を使う
static  char    gbuf[sizeof(struct hole)]; 
static  void    ff(void)
{
    uint8_t buf[sizeof(struct hole)];
    memset(buf,0xFF,sizeof(buf));  
    memcpy(gbuf,buf,sizeof(buf)); 
} 

//構造体をダンプする
static  void    memdmp(void *d1,void *d2,size_t size)
{
    uint8_t    *aptr = d1;
    uint8_t    *gptr = d2;
    for(size_t i = 0 ; i < size ;i++){
        printf("%x %x\n",aptr[i],gptr[i]);
    }
}

//メンバの内容が同じ構造体を比較する
static  void    memcmp_auto_global(void)
{
    struct  hole a = {
        .i1 = 0x12345678,
        .c  = 0xab,
        .i2 = 0x87654321
    };
    printf("比較結果=%d\n",memcmp(&a,&g,sizeof(a))) ;
    memdmp(&a,&g,sizeof(g));
}
int main(void)
{ 
    ff(); //自動変数領域をFFで汚す
    memcmp_auto_global() ;   
}

構造体の詰め物(=穴=パディング)の内容は
未規定(=コンパイラ依存)なので、
このプログラムの7行目の【穴】に何が入っているのか
わかりません。

実験ではこのプログラムは gcc と clang で実行結果が違い、
同じ gcc でも最適化レベルを変えると実行結果が変わりました。

この警告は -Wall -Wextra には含まれず、 -Wpadded を指定する必要があります。

参考:

EXP04-C. 構造体を含むバイト単位の比較を行わない

https://www.jpcert.or.jp/sc-rules/c-exp04-c.html

C-FAQ 2.8: なぜ構造体を比較することはできないのか

http://www.kouno.jp/home/c_faq/c2.html#8