이러한 코드에는 많은 이점이있을 수 있지만 불행히도 C 표준은이를 용이하게하기 위해 작성되지 않았습니다. 컴파일러는 역사적으로 표준이 요구하는 것 이상으로 효과적인 행동 보장을 제공하여 표준 C에서 가능한 것보다 훨씬 더 명확하게 그러한 코드를 작성할 수있게했지만, 컴파일러는 최근에 최적화라는 이름으로 그러한 보증을 취소하기 시작했습니다.
특히 많은 C 컴파일러는 역사적으로 (문서가 아닌 경우 설계 상) 두 구조 유형이 동일한 초기 시퀀스를 포함하는 경우 유형이 관련되지 않은 경우에도 두 유형 중 하나에 대한 포인터를 사용하여 해당 공통 시퀀스의 멤버에 액세스 할 수 있습니다. 또한 공통의 초기 시퀀스를 설정하기 위해 구조에 대한 모든 포인터는 동일합니다. 이러한 동작을 사용하는 코드는 그렇지 않은 코드보다 훨씬 깨끗하고 형식이 안전 할 수 있지만 불행히도 표준에서는 공통의 초기 시퀀스를 공유하는 구조를 동일한 방식으로 배치해야하지만 실제로는 코드를 사용하지 못합니다 한 유형의 포인터가 다른 유형의 초기 순서에 액세스합니다.
결과적으로 C로 객체 지향 코드를 작성하려면 C의 포인터 유형 규칙을 준수하기 위해 많은 후프를 뛰어 넘을 것인지 결정해야합니다 (이 결정을 일찍해야 함). 최신 컴파일러는 의도 한대로 작동하는 코드를 생성했거나 이전 스타일 포인터 동작을 지원하도록 구성된 컴파일러에서만 코드를 사용할 수 있어야한다는 요구 사항을 문서화 한 경우에도 무의미한 코드를 생성합니다 (예 : "-fno-strict-aliasing") 일부 사람들은 "-fno-strict-aliasing"을 악으로 간주하지만 "-fno-strict-aliasing"C를 "표준"C보다 몇 가지 목적으로 더 큰 의미를 제공합니다.그러나 다른 목적을 위해 중요 할 수있는 최적화를 희생합니다.
예를 들어, 기존 컴파일러에서 히스토리 컴파일러는 다음 코드를 해석합니다.
struct pair { int i1,i2; };
struct trio { int i1,i2,i3; };
void hey(struct pair *p, struct trio *t)
{
p->i1++;
t->i1^=1;
p->i1--;
t->i1^=1;
}
의 첫 번째 멤버를 증가시키고의 첫 번째 멤버의 *p가장 낮은 비트를 보완 *t한 다음의 첫 번째 멤버를 감소시키고의 첫 번째 멤버의 *p가장 낮은 비트를 보완하는*t . 최신 컴파일러는 다른 객체를 식별 p하고 t식별 하면 더 효율적 이지만 그렇지 않은 경우 동작을 변경 하는 코드 방식으로 작업 순서를 재정렬합니다 .
이 예제는 물론 의도적으로 고안되었으며 실제로는 한 유형의 포인터를 사용하여 다른 유형의 공통 초기 시퀀스의 일부인 멤버에 액세스하는 코드는 일반적으로 작동하지만 불행히도 이러한 코드가 실패하는 시점을 알 수있는 방법이 없기 때문에 불행히도 유형 기반 앨리어싱 분석을 비활성화하지 않으면 안전하게 사용할 수 없습니다.
두 포인터를 임의의 유형으로 바꾸는 것과 같은 기능을 작성하려는 경우 다소 덜 유망한 예가 발생합니다. 대다수의 "1990 년대 C"컴파일러에서 다음을 통해 달성 할 수 있습니다.
void swap_pointers(void **p1, void **p2)
{
void *temp = *p1;
*p1 = *p2;
*p2 = temp;
}
그러나 표준 C에서는 다음을 사용해야합니다.
#include "string.h"
#include "stdlib.h"
void swap_pointers2(void **p1, void **p2)
{
void **temp = malloc(sizeof (void*));
memcpy(temp, p1, sizeof (void*));
memcpy(p1, p2, sizeof (void*));
memcpy(p2, temp, sizeof (void*));
free(temp);
}
경우 *p2할당 된 스토리지에 보관되며, 임시 포인터가 할당 된 스토리지에 보관되지 않고,의 효과적인 유형의 *p2시도가 사용하는 임시 포인터의 유형 및 코드가 될 것이다 *p2임시 포인터에 맞지 않는 유형으로 type은 Undefined Behavior를 정의합니다. 컴파일러가 그러한 것을 알아 차릴 가능성은 거의 없지만, 현대의 컴파일러 철학은 프로그래머가 정의되지 않은 동작을 피할 것을 요구하기 때문에 할당 된 스토리지를 사용하지 않고 위의 코드를 작성하는 다른 안전한 수단을 생각할 수 없습니다 .