다른 유형으로 한 유형의 이동 값이 엄격한 별칭을 위반합니까?
-
20-09-2019 - |
문제
UINT32_T를 사용하여 모든 유형의 항목을 이동시키기 위해 엄격한 별칭 규칙을 위반 한 다음 다시 읽습니까? 그렇다면 UINT32_T의 배열에서 모든 유형의 배열로 Memcpy에 대한 엄격한 별칭 규칙을 위반 한 다음 요소를 다시 읽습니까?
다음 코드 샘플은 두 경우를 모두 보여줍니다.
#include <assert.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
int main(void) {
const char *strings[5] = {
"zero", "one", "two", "three", "four"
};
uint32_t buffer[5];
int i;
assert(sizeof(const char*) == sizeof(uint32_t));
memcpy(buffer, strings, sizeof(buffer));
//twiddle with the buffer a bit
buffer[0] = buffer[3];
buffer[2] = buffer[4];
buffer[3] = buffer[1];
//Does this violate strict aliasing?
const char **buffer_cc = (const char**)buffer;
printf("Test 1:\n");
for (i=0; i<5; i++)
printf("\t%s ", buffer_cc[i]);
printf("\n");
//How about this?
memcpy(strings, buffer, sizeof(strings));
printf("Test 2:\n");
for (i=0; i<5; i++)
printf("\t%s ", strings[i]);
printf("\n");
return 0;
}
32 비트 플랫폼에 대한 내 가정을 무시하십시오. 또한 요소가 uint32_t와 같은 크기가 아닌 경우, UINT32_T의 올바른 수를 패드하고 복사하는 것을 알고 있습니다. 내 질문은 그렇게하는 것이 엄격한 별칭을 위반하는지 여부에 중점을 둡니다.
해결책
첫 번째 루프 하다 기술적으로 엄격한 별칭을 위반합니다 uint32_t
유형의 lValue를 통해 물체 char *
. 그러나이 특정 사례에서 어떤 최적화가 어떤 문제를 일으킬 수 있는지 알기가 어렵습니다. 당신이 그것을 조금 변경했다면 당신은 다음과 같은 일을하고있었습니다.
printf("\t%s ", buffer_cc[0]);
buffer[0] = buffer[3];
printf("\t%s ", buffer_cc[0]);
너 ~할 것 같다 두 번 인쇄 된 동일한 문자열을 참조 - 최적화기는로드 만 권한 내에 있으므로 buffer_cc[0]
두 번째 줄은 유형의 객체 만 수정하기 때문에 한 번 레지스터로 uint32_t
.
두 번째 루프 memcpy
다시 돌아와서 괜찮습니다.
다른 팁
buffer_cc[0]
그리고 strings[3]
(예를 들어)는 동일한 메모리 위치를 참조하는 포인터이지만 동일한 유형이므로 엄격한 별칭을 위반하지 않습니다. buffer[0]
포인터가 아니므로 엄격한 별칭을 위반하지 않습니다. 앨리어싱 최적화는 포인터를 해독 할 때 발생하므로 문제가 발생할 것으로 기대하지 않습니다.
코드와 마지막 단락에서 알 수 있듯이 샘플 코드의 실제 문제는 포인터와 UINT32_T가 크기가 다를 때 발생합니다.
또한 항상 별명 a char*
엄격한 별칭을 위반하지 않고 다른 유형을 가리키는 것은 아니지만 그 반대는 아닙니다.