C 표준은이 경우 동작에 대한 요구 사항을 부과하지 않지만 많은 구현에서 표준에서 요구하는 최소값을 넘어서 많은 경우 포인터 산술 동작을 지정합니다.
어떤 부합 C 구현 및에 거의 모든 (모든 경우) C는 같은 방언, 다음과 같은 보장은 어떤 포인터 개최의 구현 p
같은 그 중 하나 *p
또는 *(p-1)
식별하는 오브젝트 :
- 임의의 정수 값을
z
제로, 포인터 값을 동일 (p+z)
과 (p-z)
에 모든면에서 동등한 것 p
둘 경우 그들은 단지 상수가 될 것이다 제외 p
하고는 z
일정하다.
- 에
q
해당하는 항목 p
에 대해 p-q
및 표현식 q-p
은 모두 0을 생성합니다.
null을 포함한 모든 포인터 값에 대해 이러한 보장을 유지하면 사용자 코드에서 일부 null 검사가 필요하지 않을 수 있습니다. 또한 대부분의 플랫폼에서 null인지 여부에 관계없이 모든 포인터 값에 대해 이러한 보장을 유지하는 코드를 생성하는 것은 null을 특별히 처리하는 것보다 더 간단하고 저렴합니다. 그러나 일부 플랫폼은 0을 더하거나 뺄 때에도 널 포인터로 포인터 산술을 수행하려는 시도를 트랩 할 수 있습니다. 이러한 플랫폼에서 보증을 유지하기 위해 포인터 작업에 추가해야하는 컴파일러 생성 널 검사의 수는 많은 경우 결과로 생략 될 수있는 사용자 생성 널 검사의 수를 크게 초과합니다.
보증을 유지하는 데 드는 비용이 크지 만 프로그램이 혜택을받을 수있는 프로그램이 거의 없다면 "null + zero"계산을 트랩하고 해당 사용자 코드를 다음과 같이 요구하는 것이 합리적 일 것입니다. 이러한 구현에는 보증이 불필요하게 만들 수있는 수동 null 검사가 포함됩니다. 그러한 수당은 보장을 유지하는 가치가 비용을 초과하는 다른 99.44 %의 구현에 영향을 미칠 것으로 예상되지 않았습니다. 그러한 구현은 그러한 보장을 유지해야하지만, 작성자는 표준 작성자가이를 말할 필요가 없어야합니다.
C ++의 작성자는 포인터 산술의 성능을 크게 저하시킬 수있는 플랫폼에서도 어떤 비용 으로든 준수 구현이 위의 보증을 유지해야한다고 결정했습니다. 그들은 유지 비용이 많이 드는 플랫폼에서도 보증의 가치가 비용을 초과 할 것이라고 판단했습니다. 이러한 태도는 C ++를 C보다 높은 수준의 언어로 취급하려는 욕구의 영향을 받았을 수 있습니다. AC 프로그래머는 특정 대상 플랫폼이 비정상적인 방식으로 (null + zero)와 같은 경우를 처리 할 때를 알 것으로 예상 할 수 있지만 C ++ 프로그래머는 그런 것들에 대해 스스로를 걱정할 것으로 예상되지 않았습니다. 따라서 일관된 행동 모델을 보장하는 것은 비용의 가치가있는 것으로 판단되었습니다.
물론 오늘날 "정의 된"항목에 대한 질문은 플랫폼이 지원할 수있는 동작과 거의 관련이 없습니다. 대신, 이제는 컴파일러가 "최적화"라는 이름으로, 이전에 플랫폼이 올바르게 처리했을 코너 케이스를 처리하기 위해 프로그래머가 수동으로 코드를 작성하도록 요구하는 것이 유행입니다. 예를 들어 n
주소에서 시작하는 문자 를 출력해야하는 코드 p
가 다음과 같이 작성되면
void out_characters(unsigned char *p, int n)
{
unsigned char *end = p+n;
while(p < end)
out_byte(*p++);
}
이전 컴파일러는 p == NULL 및 n == 0 인 경우 특별한 경우 n == 0이 필요없이 부작용없이 안정적으로 아무것도 출력하지 않는 코드를 생성합니다. 그러나 최신 컴파일러에서는 추가 코드를 추가해야합니다.
void out_characters(unsigned char *p, int n)
{
if (n)
{
unsigned char *end = p+n;
while(p < end)
out_byte(*p++);
}
}
옵티마이 저가 제거 할 수도 있고 제거 할 수도 없습니다. 추가 코드를 포함하지 않으면 일부 컴파일러는 p "널이 될 수 없음"이므로 후속 널 포인터 검사가 생략되어 실제 "문제"와 관련이없는 지점에서 코드가 중단 될 수 있다고 생각할 수 있습니다.