【C言語 memcmp】
構造体の比較で落とし穴になるパディングの注意点

最終更新日 2025年11月18日

warning: padding struct to align ‘i2’

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


■この記事の概要

この記事では、C言語でmemcmpを使った構造体の比較に関する問題を解説しています。構造体内のパディング(詰め物)が比較に影響を及ぼし、予期しない動作を引き起こす可能性があります。具体例を挙げ、比較時の注意点や安全な手法について説明しています。


■memcmpの基本的な使い方

#include <stdio.h>
#include <string.h>

int main(void){
    char    buf1[] = {1,1,1};
    char    buf2[] = {1,1,1};
    char    buf3[] = {3,3,3};

    int retx = memcmp(buf1,buf2,sizeof(buf1));
    puts(retx == 0 ? "同じ" : "違う");
    
    int rety = memcmp(buf1,buf3,sizeof(buf1));
    puts(rety == 0 ? "同じ" : "違う");
}
./a.out
同じ
違う

memcmpを文字列比較に使うのは避ける

#include <stdio.h>
#include <string.h>

int main(void){
    char    s1[32];
    char    s2[32];
    memset(s1,'A',sizeof(s1));
    memset(s2,'B',sizeof(s2));

    strcpy(s1,"abc");
    strcpy(s2,"abc");

    int retx = strncmp(s1,s2,sizeof(s1)); 
    puts(retx == 0 ? "同じ":"違う");
    
    int rety = memcmp(s1,s2,sizeof(s1));
    puts(rety == 0  ? "同じ":"違う");
}
./a.out
同じ
違う

s1,s2共に文字列としては”abc”で
同じなのですが、
memcmpは終端文字\0を超えて
指定サイズ分比較するので
strncmpと違う結果になります。


memcmpの閉じ丸カッコの位置に注意

#include <stdio.h>
#include <string.h>
int main(void){
    char    *s1 = "abc";
    char    *s2 = "abc";
    size_t  size = 3;
    puts(strncmp(s1,s2,size  == 0)  ?"同じ":"違う");
    puts(strncmp(s1,s2,size) == 0   ?"同じ":"違う");
    puts(memcmp(s1,s2,size   == 0)  ?"同じ":"違う");
    puts(memcmp(s1,s2,size)  == 0   ?"同じ":"違う");
}
./a.out
違う
同じ
違う
同じ

閉じ丸カッコの位置が間違っているので誤動作します。


■memcmpで構造体の穴にはまる

#include    <stdio.h>
#include    <string.h>
#include    <stdint.h>
typedef struct  hole    {
    uint32_t    i1 ;
    uint8_t     c  ;// 3byteの穴    
    uint32_t    i2 ;
} hole ;
static hole g   = {1,2,3};
void    cmp(void){//メンバの内容が同じ構造体を比較する  
    hole a      = {1,2,3};
    int ret = memcmp(&a,&g,sizeof(hole)) ;
    puts(ret == 0 ? "同じ" : "違う") ;
}
//自動変数領域全部(穴も)をFFで汚す
void    ff(void){
    char buf[sizeof(hole)] ;
    memset(buf,'F',sizeof(buf));
    printf("[%-12.12s]\n",buf);
} 
int main(void){ 
    ff(); //自動変数領域をFFで汚す
    cmp();  
}
./a.out
[FFFFFFFFFFFF]
違う

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

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

参考:

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