6
typedef struct { 
    void * field1; 
} s1; 

void func1(void) { 
    s1 my_s1; 
    s1 * __restrict my_s1_ptr = &my_s1; 
    *((int*)((char*)my_s1_ptr->field1 + 4)) = 0; 
    *((int*)((char*)my_s1_ptr->field1 + 8)) = 1; 
    *((int*)((char*)my_s1_ptr->field1 + 12)) = 2; 
    *((int*)((char*)my_s1_ptr->field1 + 16)) = 3; 
} 

인텔 컴파일러 버전 11.1 및 gcc 버전 4.6의 경우 컴파일러에서 마지막 4 개 문 각각에 대해 my_s1_ptr-> field1을 다시로드하는 것으로 보입니다. __restrict에 대한 나의 이해는 나에게 마지막 3 개의 부하가 중복되어야하고 제거 될 수 있다고 제안합니다. 네, 코드가 이상하다는 것을 압니다 만,이 방법으로 구조화 된 이유가 있습니다. 중복로드를 제거하기 위해 컴파일러를 얻을 수 있기를 바랍니다. 그걸 어떻게하도록 설득 시키는가?c99 __restrict 및 컴파일러 최적화

+0

최적화를 사용하여 컴파일 했습니까? 그리고 왜 C99 키워드 인'restrict'보다는'__restrict'를 사용하고 있습니까? –

+0

최적화로 컴파일했는데 __restrict와 restrict는 큰 차이가 없습니다. – DrTodd13

+0

난 구조체에 대한 포인터 대신 필드에 대한 포인터에 대해 여러 변형을 시도했지만 아무 것도 변경하지 않았다. 실제 코드에서는 field1이 가리키는 필드를 가리키는 포인터가 여러 개있을 수 있으므로 field1에 restrict를 추가하는 것은 유효하지 않습니다.하지만로드를 제거하지는 않았지만 시도해 보았습니다. field1을 제한 지역 변수 포인터에 복사하면 중복로드가 제거되지만이 방법은 프로그램의 의미를 위반한다고 말합니다. – DrTodd13

답변

3

s1 * __restrict은이 포인터가 특정 s1에 대한 유일한 포인터이므로 해당 유형의 별칭이 없음을 의미합니다. 다른 포인터 유형 (예 : void*, int* 또는 char*)에 대한 별칭이 없음을 의미하지 않습니다.

char*은 특히 다른 유형의 바이트에 액세스하는 데 사용하도록 허용되어 있기 때문에 컴파일러에서 특히 골칫거리입니다. (char은 바이트를 의미하며 다른 유형의 기본 메모리에 액세스하는 데 사용될 수도 있음).

컴파일러가 할당이 절대로 바뀌지 않는다고 증명할 수없는 경우에는 포인터를 다시로드해야합니다. 예를 들어 void* field1이 자신을 가리키고 있지 않다는 것을 어떻게 알 수 있습니까?


그리고 모든 캐스트가없는이 작업이 마음에 들지 않습니까?

int* p = my_s1.field1; 
p[1] = 0; 
p[2] = 1; 
p[3] = 2; 
p[4] = 3; 

int 가정하면 4 바이트이고, 그 field1 실제로 이들의 배열을 가리킨다.

+0

"'char'는 또한 바이트를 의미합니다"-> 컴파일러는'char' 또는'unsigned char'를 조심해야합니까? (확실하지 않은, 그 이유는 내가 묻고있어 : – Mehrdad

+0

우리는 signedness를 알고 있기 때문에 대부분'unsigned char'을 사용합니다, 그러나 평범한'char'은 동일 할 수도 있고 또한 메모리에 접근 할 수 있습니다 서명 여부). –

+0

"'s1 * __restrict'는 이것이 특정's1'에 대한 유일한 포인터라는 것을 의미합니다 :'__restrict'에 대해서는 알지 못합니다 만, 이것은 C99의'restrict'에 해당하지 않습니다. 예를 들어'void * memcpy (void * restrict s1, const void * restrict s2, size_t n);'. 6.7.3.1 절은 객체에 기반한 포인터 표현의 개념을 정의하고 포인터 변환을 제공하지 않는다 ('memcpy'는 그대로 프로토 타이핑이 가능하다). –