■strNcmpとmemcmpが違う例
#include <stdio.h>
#include <string.h>
char s1[] = "abc\0DEF" ; //abc+DEF
char s2[] = "abc\0XYZ" ; //abc+XYZ
int main(void){
if(strncmp(s1,s2,sizeof(s1)) == 0)
printf("strncmpは'¥0'を終端とする:%sと%sは同じ\n",&s1[0],&s2[0]);
if(memcmp(s1,s2,sizeof(s1)) != 0)
printf("memcmpは'¥0'を終端としない:%sと%sは違う\n",&s1[4],&s2[4]);
}
●違いその1
strncmp()は終端文字¥0までしか比較しない
memcmp()は終端文字¥0を超えて比較する。
●違いその2
strncmp()の第1,第2引数には char * 型しか渡せません。
(キャストしてコンパイラを騙し警告を無視するのは論外とします)
memcmp()の第1,第2引数はvoid *型なのでデータのアドレスならば
何でも渡せます。
●実行結果
strncmpは'¥0'を終端とする:abcとabcは同じ
memcmpは'¥0'を終端としない:DEFとXYZは違う
■strNcpyとmemcpyが違う例
//gcc -g f1.c -fsanitize=address
#include <stdio.h>
#include <string.h>
static char コピー元小[8] = "abc\0xyz";
static char コピー先大[16];
int main(void){
//'\0'を終端とするstr系
strncpy(コピー先大,コピー元小,sizeof(コピー先大));
printf("%s:%s\n",&コピー先大[0],&コピー先大[4]);
//'\0'を終端としないmem系(バグあり)
memcpy(コピー先大,コピー元小,sizeof(コピー先大));//★
printf("%s:%s\n",&コピー先大[0],&コピー先大[4]);
}
●違いその1
strncpy()は終端文字¥0までしか転送しません。
memcpy()は終端文字¥0を超えて指定のサイズまで転送します。
●違いその2
第2引数が第3引数より短い場合、
strncpy()は残りを¥0で埋めます。
memcpy()は第2引数で領域外参照が発生して動作不明となります。
※このプログラムの例では転送元は8byteしかないのに16byte読み込むので領域外参照のバグとなります。
gcc -g -fsanitize=address でコンパイルすると異常終了しました。
■文字列比較にmemcmpを使ってバグった例
#include <stdio.h>
#include <string.h>
int main(void){
char str1[1024]="ABCD";
char str2[1024];
strcpy(str2,"ABCD");
puts("memcmp");
if(memcmp(str1,str2,sizeof(str1)) == 0){
printf("%sと%sは同じ\n",str1,str2);
}else{
printf("%sと%sは違う\n",str1,str2);
}
puts("strncmp");
if(strncmp(str1,str2,sizeof(str1)) == 0){
printf("%sと%sは同じ\n",str1,str2);
}else{
printf("%sと%sは違う\n",str1,str2);
}
}
(1)str1[1024]は先頭の”ABCD”と残り全部が0保証されます。
(2)str2[1024]は先頭の”ABCD”と終端文字の\0が保証されますが、
残りは全部ゴミの値です。
(3)memcmpは1024byte全部比較するので
ゴミの内容で結果が変わります。
(4)strncmpは先頭5byte(ABCDと終端文字\0)を比較して終了するのでstr1とstr2は同じ文字列となります。
➡str1,str2のサイズ1024を小さくしてみましょう。
結果がコロコロ変わる
非常に恐ろしいバグと分るでしょう。
参考:
C-FAQ 13.2:任意のバイトをコピーするときには、普通は memcpy()のほうがstrncpy()よりも適切なルーチンである。
http://www.kouno.jp/home/c_faq/c13.html#2