memset、memmcpy、memmove実装とその違い
2684 ワード
この3つの関数は本当に古典的で、自分で実現しなければなりません.
3つの関数のプロトタイプは次のとおりです.
次のようになります.
//の表記を採用しないのは、パケットが警告を出すからです:warning:value computed is not used
不快に見える.
注意事項:
(1)memsetを使用する場合は、最下位または最下位の次の位置を「0」とする.
prinfの文字列が1つあるとき、printf関数は'0に出会って停止するからです.最初の例では、buffer[20]はすべて‘1’であり、終了には‘0’がないので、印刷された結果は不確定であると考えられる.もちろん、正しいかもしれませんが、それは運がいいだけです.
(2)memcpyとstrcpyの違い:
実際の違いは1つだけで、strcpyの操作オブジェクトはchar*しかなく、memcpyの操作オブジェクトはvoid*です.(どんなタイプでもOK).実際、memcpyの実装では、(void*)を(char*)に置き換えて作られていますが、実はstrcpyと同じです.
(3)memmoveとmemcpyの違い:
違いはmemmoveがメモリ区間が重なる場合を考慮し、memcpyはしません.
この問題については、以下の画像で説明できます.
メモリ区間が重複している場合は、メモリ区間が重複していない場合と次のようになります.
desがsrc+2であると仮定し、memcpy処理に従って最初からコピーを開始すると、次の悲劇が発生します.
srcのメモリは汚染されており、このとき*desの先頭のメモリを印刷すると、'0'が上書きされているため、定義されていない場合があります.
121212121212????"
1234
3つの関数のプロトタイプは次のとおりです.
void* memset(void *des, int val, size_t size)
void * memcpy(void *des, const void* src, size_t size)
void * memmove(void *des, const void *src, size_t size)
次のようになります.
void* memset(void *des, int val, size_t size) {
void *start = des;
while (size--) {
*(char*) des = (char) val;
des = (char *) des + 1;
// (char*) des++;
// des = (char* )des + 1;
}
return start;
}
void * memcpy(void *des, const void* src, size_t size) {
void *ret = des;
while (size--) {
*(char *) des = *(char *) src;
des = (char *)des + 1;
src = (char *)src + 1;
// (char *) des++;
// (char *) src++;
}
return ret;
}
void * memmove(void *des, const void *src, size_t size) {
void *ret = des;
if (des < src || (char *) des > (char *) src + size - 1) {
while (size--) {
*(char *) des = *(char *) src;
des = (char *) des + 1;
src = (char *)src + 1;
// (char *) src++;
// (chr *) des ++;
}
}else{
des = (char *)des + size - 1;
src = (char *)src + size - 1;
while (size -- > 0){
*(char *) des = *(char *) src;
// (char *) des--;
// (char *) src--;
des = (char *)des - 1;
src = (char *)src - 1;
}
}
return ret;
}
//の表記を採用しないのは、パケットが警告を出すからです:warning:value computed is not used
不快に見える.
注意事項:
(1)memsetを使用する場合は、最下位または最下位の次の位置を「0」とする.
char buffer[20] = "hello";
memset(buffer, '1', sizeof(char)*20);
printf("%s
",buffer);
:111111111111111111110@
char buffer[20] = "hello";
memset(buffer, '1', sizeof(char)*20);
buffer[20] = '\0';
printf("%s
",buffer);
:11111111111111111111
prinfの文字列が1つあるとき、printf関数は'0に出会って停止するからです.最初の例では、buffer[20]はすべて‘1’であり、終了には‘0’がないので、印刷された結果は不確定であると考えられる.もちろん、正しいかもしれませんが、それは運がいいだけです.
(2)memcpyとstrcpyの違い:
実際の違いは1つだけで、strcpyの操作オブジェクトはchar*しかなく、memcpyの操作オブジェクトはvoid*です.(どんなタイプでもOK).実際、memcpyの実装では、(void*)を(char*)に置き換えて作られていますが、実はstrcpyと同じです.
(3)memmoveとmemcpyの違い:
違いはmemmoveがメモリ区間が重なる場合を考慮し、memcpyはしません.
この問題については、以下の画像で説明できます.
メモリ区間が重複している場合は、メモリ区間が重複していない場合と次のようになります.
desがsrc+2であると仮定し、memcpy処理に従って最初からコピーを開始すると、次の悲劇が発生します.
srcのメモリは汚染されており、このとき*desの先頭のメモリを印刷すると、'0'が上書きされているため、定義されていない場合があります.
char buffer5[10] = "1234";
memcpy(buffer5 + 2, buffer5, sizeof(buffer5));
printf("%s
", buffer5);
char buffer6[10] = "1234";
memmove(buffer6 + 2, buffer6, sizeof(buffer6));
printf("%s
",buffer6 + 2);
実行結果:121212121212????"
1234