쾌락없는 책임 (공부)/C++ 짜잘이

C++ fill_n vs memset, 무슨 차이가 있을까

허스크 2022. 2. 28. 23:06
반응형

서론

 알고리즘 문제 풀이를 하다 보면 배열이나 vector 등을 초기화해야 하는 일이 많습니다. 첫 생성시 0으로 초기화 된다는 사실이 있지만 이것도 환경따라 다를 수 있고 또는 0이 아닌 다른 값으로 초기화해야 하는 일이 있습니다.

 그럴때 for문을 사용하기 싫어서 fill_n, memset 등의 함수를 사용해서 값을 세팅하게 됩니다. 그런데 언제 한번 2차원 배열 등을 사용할 때 초기화가 제대로 되지 않는 경우가 있었습니다. 그래서 오늘 두 함수에 대한 차이점을 알아보기 위해서 글로 정리하게 되었습니다.

 

두 함수의 차이

 일단 헤더부터 차이가 있습니다. fill 관련 함수들은 <algorithm> 헤더에 있으며 memset는 <cstring>에 있습니다. 그리고 memset의 경우 c 에서 파생된 함수로 fill_n 보다 조금 더 빠르다는 이야기가 있지만 실제로 체감할 정도는 아니며 gcc6.2 에서는 둘다 같은 코드를 만들어 낸다는 이야기도 있습니다.

#include <iostream>
#include <algorithm>
#include <cstring>
#include <limits>
using namespace std;

int long long arr[5];
void printArr(){
    for(int i = 0; i < 5; i++){
        cout << arr[i] << " ";
    }
    cout << '\n';
}
int main(){
    arr[1] = __LONG_LONG_MAX__;

    printArr(); // 0 9223372036854775807 0 0 0 

   memset(arr, 1, sizeof(arr));
   printArr(); // 72340172838076673 72340172838076673 72340172838076673 72340172838076673 72340172838076673 

   fill_n(arr, sizeof(arr), 1);
   printArr(); // 1 1 1 1 1
}

 

 제일 큰 차이는 위 코드에서 보이게 됩니다. memset으로 long long 배열을 1로 초기화 하려고 했는데 이상한 값이 나오게 됩니다.

   cout << bitset<16>(arr[1]) << '\n'; // 0000000100000001

 이걸 16진수로 출력을 해보면 00000001 이 반복되는 모습을 볼 수 있습니다. 아마도 8바이트 단위로 초기화를 해주는것 같아서 이런 문제가 발생한 것 같습니다. 그래서 0, -1을 제외한 경우 memset을 사용할 때 데이터 타입의 길이에 따라서 원하는 값이 나오지 않을 수 있습니다!

 

결론

결론을 내자면 데이터타입에 따라, 초기화 하는 값이 0, -1이 아니라면 fill_n 사용을 고려하자!


참고 사이트

- 속도와 관련한 이야기

 

What performance can I expect from std::fill_n(ptr, n, 0) relative to memset?

For an iterator ptr which is a pointer, std::fill_n(ptr, n, 0) should do the same thing as memset(ptr, 0, n * sizeof(*ptr)) (but see @KeithThompson's comment on this answer). For a C++ compiler in...

stackoverflow.com

 

- memset이 넘기는 단위와 관련한 이야기

 

Which is faster/preferred: memset or for loop to zero out an array of doubles?

double d[10]; int length = 10; memset(d, length * sizeof(double), 0); //or for (int i = length; i--;) d[i] = 0.0;

stackoverflow.com

 

 

std::memset - cppreference.com

Converts the value ch to unsigned char and copies it into each of the first count characters of the object pointed to by dest. If the object is a potentially-overlapping subobject or is not TriviallyCopyable (e.g., scalar, C-compatible struct, or an array

en.cppreference.com

 

 

std::fill_n - cppreference.com

(1) template< class OutputIt, class Size, class T > void fill_n( OutputIt first, Size count, const T& value ); (until C++11) template< class OutputIt, class Size, class T > OutputIt fill_n( OutputIt first, Size count, const T& value ); (since C++11) (until

en.cppreference.com

 

반응형