2009-08-20 4 views
5

일부 루프를 풀어서 일부 코드를 최적화하고 있습니다 (예, 컴파일러를 사용하여 컴파일러를 선택해야 컴파일러를 선택하지 않을 것입니다). 미래의 일부 편집으로 인해 데이터 크기가 변경되는 경우 코드가 우아하게 저하됩니다. 같은매크로에 해당하는 C 크기의 매크로

뭔가 :

typedef struct { 
    uint32_t alpha; 
    uint32_t two; 
    uint32_t iii; 
} Entry; 

/*...*/ 

uint8_t * bytes = (uint8_t *) entry; 
#define PROCESS_ENTRY(i) bytes[i] ^= 1; /*...etc, etc, */ 
#if (sizeof(Entry) == 12) 
    PROCESS_ENTRY(0);PROCESS_ENTRY(1);PROCESS_ENTRY(2); 
    PROCESS_ENTRY(3);PROCESS_ENTRY(4);PROCESS_ENTRY(5); 
    PROCESS_ENTRY(6);PROCESS_ENTRY(7);PROCESS_ENTRY(8); 
    PROCESS_ENTRY(9);PROCESS_ENTRY(10);PROCESS_ENTRY(11); 
#else 
# warning Using non-optimized code 
    size_t i; 
    for (i = 0; i < sizeof(Entry); i++) 
    { 
     PROCESS_ENTRY(i); 
    } 
#endif 
#undef PROCESS_ENTRY 

이되지 sizeof은 사전 프로세서를 사용할 수없는 때문에, 물론, 작업 (적어도, 그 this answer가 표시 같았다 기능).

sizeof을 C 매크로와 함께 사용할 데이터 구조를 얻는 데 사용할 수있는 간단한 방법이 있습니까? 아니면 그냥 SOL입니까?

+0

음, sizeof() **는 ** 매크로입니다. 최소한 내장 매크로. – Havenard

+5

sizeof는 매크로가 아니며 모양이나 형식에 관계없이 –

+2

크기는 매크로가 아니지만 offsetof는 매크로입니다. sizeof는 더 많은 연산자입니다. –

답변

17

을 당신은 할 수 없습니다 선행 처리기에서 처리하지만 필요는 없습니다. 그냥 매크로에서 일반 if을 생성합니다

#define PROCESS_ENTRY(i) bytes[i] ^= 1; /*...etc, etc, */ 
if (sizeof(Entry) == 12) { 
    PROCESS_ENTRY(0);PROCESS_ENTRY(1);PROCESS_ENTRY(2); 
    PROCESS_ENTRY(3);PROCESS_ENTRY(4);PROCESS_ENTRY(5); 
    PROCESS_ENTRY(6);PROCESS_ENTRY(7);PROCESS_ENTRY(8); 
    PROCESS_ENTRY(9);PROCESS_ENTRY(10);PROCESS_ENTRY(11); 
} else { 
    size_t i; 
    for (i = 0; i < sizeof(Entry); i++) { 
     PROCESS_ENTRY(i); 
    } 
} 

sizeof는 상수 표현 및 일정에 대한 상수를 비교하는도 일정하다. 모든 제정신 C 컴파일러는 컴파일 시간에 항상 false 인 분기를 최적화합니다. 상수 폴딩은 가장 기본적인 최적화 중 하나입니다. 그래도 #warning을 잃게됩니다.

+0

약간 다른 각도에서 문제를 보는 것이 좋습니다. +1과 명성! – qrdl

9

autoconf 또는 다른 빌드 구성 시스템을 사용하는 경우 구성시 데이터 구조의 크기를 확인하고 헤더 (예 : #define SIZEOF_Entry 12)를 쓸 수 있습니다. 물론 이것은 크로스 컴파일 할 때 더 복잡해 지지만 빌드와 타겟 아키텍처가 같다고 가정합니다.

그렇지 않으면 운이 없습니다.

-1

구조체에 가능한 한 가장 작은 크기를 원하거나 4 바이트 경계에 맞추려면 크기가 채워지거나 정렬 된 특성을 사용할 수 있습니다. 비주얼 C에서

++, 당신은 #pragma pack을 사용할 수 있으며, GCC에서 사용할 수있는 __attribute __ ((포장))와 __attribute __ ((정렬 (NUM 바이트)) 당신은 운이있어

+0

크기는주지 않습니다. 또한 패킹이 공간을 절약 할 수는 있지만 시간이 걸릴 가능성이 있으며 그게 그가 얻으려고하는 것입니다. –

+0

@David Thornley : 크기를 제공하지 않지만이 코드 블록에서 원하는 작업을 수행합니다. 구조체를 패킹함으로써 그는 패딩이 없다는 것을 확실히 알 수 있습니다. 따라서 구조체 *는 정확히 12 바이트 (또는 각 항목의 크기의 합)이므로 선행 처리기 매크로를 사용할 필요가 없습니다. 구조체의 크기를 찾는다. PROCESS_ENTRY는 패딩되지 않은 구조체에서 바이트 수준 액세스를 사용하므로 구조체를 패딩하면 패딩 걱정없이이 매크로를 사용할 수 있습니다. –

+0

필자는 일반적으로 아무렇게나 간섭하지 않는 것이 가장 좋으며 옵티마이 저는이 작업을 수행하게하는 것이 가장 좋습니다 (특히 대부분의 프로그래머보다 훨씬 뛰어나다). –

5

-. 전처리

이런 경우에 구조체의 크기가 무엇인지를 알기 위해 #define 상수를 정의 할 수 있습니다. 그런 다음, struct가 무엇인지 알 수 없습니다. 실제로 네거티브 크기의 배열 트릭을 사용하여 크기와 같다고 정적으로 주장합니다.컴파일러가 컴파일 할 때 분기 조건을 평가하고 죽은 코드를 제거 할 수 있는지 확인하십시오. 그것은 큰 질문이 아닙니다. 도움이되지 않습니다 당신이 컴파일시에 적절한 루프에 파견하는 컴파일러의 원인이 템플릿을 사용하여 C++에서이 작업을 수행 할 수있는 능력이있는 경우

+0

+1은 '최적화 프로그램이 최적화하는지 확인하십시오'제안입니다. –

+0

#warning보다는 assert()를 사용하는 것도 좋은 방법입니다. 당신은 정말로 우아한 퇴화를 원합니까? 아니면 문제를 해결할 수 있도록 문제에 대해 명확히 알리고 싶습니까? –

+0

그리고 두 가지 이유가 있습니다. 하나는 예상치 못한 패딩입니다 (이 경우에는 오류가 발생하기 때문에 컴파일러 관련 pragma를 사용하여 구조를 패킹 할 수 있습니다). 그리고 하나는 필드를 추가합니다 (이 경우 #define을 업데이트하여 새 크기를 나타내고, 새 크기를 처리하기 위해 언 롤링 루프를 업데이트할지 여부를 결정할 수도 있습니다). 그래서 실제로, 구조체의 정의 시점에서 주장을하고, 또한 언 롤링 시점에서 경고합니다. –

1

이것은 아마도,하지만 :

template <std::size_t SizeOfEntry> 
void process_entry_loop(...) 
{ 
    // ... the nonoptimized version of the loop 
} 

template <> 
void process_entry_loop<12>(...) 
{ 
    // ... the optimized version of the loop 
} 

// ... 

process_entry_loop<sizeof(Entry)>(...); 
+2

좋은 생각이지만 sizeof (Entry) 템플릿 매개 변수를 만드는 것이 더 명확하고 12를 전문으로합니다. –

+0

+1 팁 - 나는 그것을 좋아합니다! – fbrereto

1

다른 두 가지 접근 방법이 마음에 들지 있습니다. 풀린 루프를 작성하기 위해 작은 응용 프로그램을 작성하거나 Duff's device의 변형을 구조체의 예상 크기와 함께 사용하십시오.

+1

Duff의 장치보다 느린 코드를 생성하는 최신 컴파일러는별로 좋은 컴파일러가 아닙니다. –

+0

코드 크기에 대해 편집증이 얼마나 의존하고 있지 않습니까? 컴파일러는 반드시 코드의 크기에 12를 곱하면됩니다. 프로파일 러 입력이 없으면 옵티마이 저는 속도를 얻기 위해 코드 크기를 지불 할 가치가있는 루프를 알 수있는 방법이 없습니다. 모든 것을 푸는 것은 큰 코드, 많은 icache misses 및 느려짐을 초래합니다. 반면에 언 롤링 할 루프를 지능적으로 선택할 수 있습니다 (또는 더 지능적으로 프로파일 러 데이터를 사용하여 최적화 할 수있는 컴파일러 사용). 더프의 장치가 이제는 내가 모르는 더 새롭고 좋은 기법으로 인해 쓸모 없다는 것을 의미하지 않는다면. –