2017-02-28 3 views
6

FreeBSD's generic implementation of memchr을 수행합니다FreeBSD의 memchr 구현이 포인터를 증가시키는 이유는 무엇입니까?

void * 
memchr(const void *s, int c, size_t n) 
{ 
    if (n != 0) { 
     const unsigned char *p = s; 

     do { 
      if (*p++ == (unsigned char)c) 
       return ((void *)(p - 1)); 
     } while (--n != 0); 
    } 
    return (NULL); 
} 

을 불필요하게 복잡한 것 같다 나에게하는; 으로 확인하십시오 do - while 그냥 p 선언을 피하기 위해 완전히 무의미한 것 같습니다. 그러나, 나는 루프 본체가하는 이유에 특히 관심이 : 대신 더 간단의

if (*p++ == (unsigned char)c) 
    return ((void *)(p - 1)); 

:

if (*p == (unsigned char)c) 
    return ((void *) p); 
++p; 

조건과 후행 증가가 일부 컴파일러에 대한 몇 가지 최적화 혜택이 인라인합니까/플랫폼?

+1

컴파일러가 생성하는 (최적화 된) 기계 코드를 확인 했습니까? 당신의 접근 방식이 다른 점은 무엇입니까?'p'의 _definition_은 코드를 생성합니까? 그리고 네, 당신은 그 코드가 가장 많이 쓰여졌을 때와 그 당시의 좋은/나쁜 컴파일러가 어떻게 최적화되었는지를 생각해 보지 못했습니다. 상당수의 CPU에는 "0이 아닌 경우 감소 및 분기"명령어가 있습니다. – Olaf

+0

@Olaf god와 구현을 비교하기 위해 godbolt를 사용했습니다 (-O3을 사용하고 -O를 사용). 나는 어셈블리에 익숙하지 않지만, 간단한 버전은 더 적은 명령어를 생성하는 것으로 보인다. – jamesdlin

+0

내 의견을 다시 읽고, 나는 꽤 많이 추가했다. BSD를 실행하는 모든 대상을 확인합니까? x86은 실제로 널리 보급 된 플랫폼이 아닙니다. 이 코드는 심지어 수십 년 동안 x86과 ARM을 능가하는 8 비트와 16 비트 MCU에도 사용될 수 있습니다. – Olaf

답변

2

포인터 증가 이후의 경우 (예 : PCC) DEC 기계에서 자동 증가 주소 지정 모드를 사용할 수 있습니다 (예 : 주석의 Mark Plotnick 언급).

모든 DEC 머신은 자동 증가 어드레싱을 지원하기 때문에 이러한 코딩 루프는 한 번 매우 일반적입니다 (BTW, m68k는 동일한 최적화를 지원합니다).

루프 반면에 do-while 루프는 단순히 naïf 컴파일러에서 p을 피하는 것뿐만 아니라 더 나은 코드를 생성하기 때문입니다.

아니요 이어야합니다.은 최신 컴파일러에서 차이가 있습니다.

+0

'p' 설정을 피하는 것은 당연히 명령어를 저장하지 않습니다 –

+0

naïf 컴파일러에서는 아무런 차이가 없지만 분기의 위치 만 변경하기 때문에'n = 0'에 대해서만 의미가 있습니다. –

3

첫 번째 : 이것은 순수한 추측입니다. 나는이 코드를 작성하지 않았고 추측을 확인할 수도 없었다. 버전 B에 해당 후에 서열화 반면

// Version A 
if (*p++ == (unsigned char)c) 
    return ((void *)(p - 1)); 

// Version B 
if (*p == (unsigned char)c) 
    return ((void *) p); 
++p; 

버전 A의 증가가 if의 코드 블록 전에 서열화되고, 상기 코드의 두 버전 사이의 하나 개의 매우 중요한 의미 차이가

있어 블록.

따라서 버전 A에서 증가 코드는 if에서 생성 될 가능성이 높은 분기 명령어 앞에 배치됩니다. 적어도 우리는 IMO가 코드가 작성된 시점 (1988?)에 C 코드에서 컴파일러로 어셈블리를 직접 변환한다고 가정 할 수 있습니다.

일부 증가/감소 플랫폼에 대해 최적화 이점이있는 상태에서 후행 증가를 인라이닝합니까?

지점은 그 지점 지침이 아키텍처에서 비교적 간단한 최적화를 허용하기 전에 증가를 갖는 delay slot : 당신이 거기에 NOP를하는 대신 그 지연 슬롯에 증가를 이동할 수 있습니다.

따라서 버전 A는 버전 B보다 루프 반복 당 하나의 명령어가 적으므로 함수가 반환 될 때 한 번 감소합니다. 그것은 (마이크로) 최적화입니다.