developer tip

작은 정수 배열 지우기 : memset 대 for 루프

optionbox 2020. 12. 31. 08:12
반응형

작은 정수 배열 지우기 : memset 대 for 루프


정수 / 부동 배열을 0으로 만드는 두 가지 방법이 있습니다.

memset(array, 0, sizeof(int)*arraysize);

또는:

for (int i=0; i <arraysize; ++i)
    array[i]=0;

분명히 memset은 큰 arraysize. 그러나 memset의 오버 헤드가 실제로 for 루프의 오버 헤드보다 큰 지점은 어디입니까? 예를 들어, 크기가 5 인 배열의 경우 어떤 것이 가장 좋을까요? 첫 번째, 두 번째 또는 아마도 언 롤링 된 버전 :

array[0] = 0;
array[1] = 0;
array[2] = 0;
array[3] = 0;
array[4] = 0;

모든 가능성에서 memset ()은 컴파일러에 의해 인라인됩니다 (대부분의 컴파일러는이를 '내장'으로 취급합니다. 즉, 가장 낮은 최적화에서 또는 명시 적으로 비활성화하지 않는 한 기본적으로 인라인됨을 의미합니다).

예를 들어, 다음은 GCC 4.3의 일부 릴리스 노트입니다 .

블록 이동 ( memcpy) 및 블록 세트 ( memset) 의 코드 생성 이 다시 작성되었습니다. GCC는 이제 복사되는 블록의 크기와 최적화되는 CPU를 기반으로 최상의 알고리즘 (루프, 언 롤링 된 루프, rep 접두사가있는 명령어 또는 라이브러리 호출)을 선택할 수 있습니다. 새로운 옵션 -minline-stringops-dynamically이 추가되었습니다. 이 옵션을 사용하면 알 수없는 크기의 문자열 작업이 확장되어 작은 블록이 인라인 코드로 복사되는 반면 큰 블록의 경우 라이브러리 호출이 사용됩니다. 따라서 -minline-all-stringops라이브러리 구현이 캐시 계층 힌트를 사용할 수있을 때보 코드가 더 빠릅니다 . 특정 알고리즘을 선택하는 휴리스틱은를 통해 덮어 쓸 수 있습니다 -mstringop-strategy. 새로 memset0과 다른 값 인라인됩니다.

컴파일러가 당신이 준 대체 예제와 비슷한 일을 할 수는 있지만 가능성은 적을 것입니다.

그리고 grep부팅의 의도가 무엇인지 한눈에 쉽게 알 수 있습니다 (루프도 특히 어렵지 않습니다).


Michael이 이미 언급했듯이 gcc와 나는 대부분의 다른 컴파일러가 이미 이것을 매우 잘 최적화한다고 생각합니다. 예를 들어 gcc는 이것을

char arr[5];
memset(arr, 0, sizeof arr);

으로

movl  $0x0, <arr+0x0>
movb  $0x0, <arr+0x4>

그것보다 더 나아지지는 않습니다 ...


측정하지 않고 질문에 답할 수있는 방법은 없습니다. 컴파일러, CPU 및 런타임 라이브러리 구현에 전적으로 의존합니다.

memset ()은 버퍼 오버 플로우, 매개 변수 반전의 경향이 있고 '바이트 단위'만 지우는 불행한 능력이 있기 때문에 "코드 냄새"가 될 수 있습니다. 그러나 극단적 인 경우를 제외하고는 '가장 빠르다'는 것이 안전한 내기입니다.

일부 문제를 피하기 위해 매크로를 사용하여 래핑하는 경향이 있습니다.

#define CLEAR(s) memset(&(s), 0, sizeof(s))

이것은 크기 계산을 회피하고 길이 및 값 매개 변수를 바꾸는 문제를 제거합니다.

간단히 말해서, "내부에서"memset ()을 사용하십시오. 의도 한대로 작성하고 컴파일러가 최적화에 대해 걱정하게하십시오. 대부분은 엄청나게 잘합니다.


이 코드 자체를 고려하면 이미 말한 바 있습니다. 그러나 내가 아무것도 모르는 프로그램에서 그것을 고려하면 다른 일을 할 수 있습니다. 예를 들어이 코드가 배열을 지우기 위해 매번 실행되는 경우 전역 변수에 할당 된 0 요소의 새 배열을 지속적으로 할당하는 스레드를 실행할 수 있습니다. 단순히 가리 킵니다.

이것은 세 번째 옵션입니다. 물론 두 개 이상의 코어가있는 프로세서에서 코드를 실행할 계획이라면 이는 의미가 있습니다. 또한 이점을 확인하려면 코드를 두 번 이상 실행해야합니다. 한 번만 실행하는 경우 0으로 채워진 배열을 선언 한 다음 필요할 때 가리킬 수 있습니다.

이것이 누군가를 도울 수 있기를 바랍니다.

참조 URL : https://stackoverflow.com/questions/1134103/clearing-a-small-integer-array-memset-vs-for-loop

반응형