C에서 Null 포인터를 사용하여 정적 멤버에 액세스
C에서는 일반적으로 초기화되지 않은 클래스 또는 구조체의 멤버에 액세스하는 것으로 이해됩니다. 포인터는 정의되지 않은 동작입니다. 그러나 정적 멤버는 특이한 예외를 보이는 것 같습니다. 다음 코드 조각은 이 동작을 보여줍니다.
<code class="cpp">#include <iostream> class demo { public: static void fun() { std::cout << "fun() is called\n"; } static int a; }; int demo::a = 9; int main() { demo *d = nullptr; d->fun(); std::cout << d->a; return 0; }</code>
이 코드를 컴파일하고 실행하면 오류 없이 예상되는 출력("fun()이 호출됨" 및 "9")이 생성됩니다. 이는 질문을 제기합니다: 이 접근 방식에 어떤 해가 있습니까?
동작 이해
이 동작을 이해하려면 정적 멤버 액세스의 정의를 자세히 살펴보는 것이 중요합니다. C에서. 언어 표준에 따르면 정적 멤버에 액세스하는 데 사용되는 도트 연산자(.)는 본질적으로 null 포인터를 역참조한 다음 이 포인터가 가리키는 개체의 멤버에 액세스하는 것과 같습니다. 이 경우 널 포인터는 클래스의 인스턴스가 아닌 클래스의 정적 멤버를 참조합니다.
이는 널 포인터를 사용한 정적 멤버 액세스가 본질적으로 정의되지 않은 동작이 아닌 이유를 설명합니다. 중요한 측면은 *d 또는 d->a와 같은 액세스 표현식이 lvalue에서 rvalue로의 변환이나 초기화되지 않은 포인터를 처리할 때 일반적으로 정의되지 않은 동작을 트리거하는 기타 작업 없이 평가된다는 것입니다.
널 포인터를 통한 간접
그런 다음 질문이 생깁니다. 널 포인터를 통한 간접 참조는 항상 정의되지 않은 동작을 초래합니까? 대답은 놀랍게도 미묘합니다. 바로 이 주제를 다루는 공개 CWG 문제(#232)가 있으며, 널 포인터를 통한 간접 참조만으로는 정의되지 않은 동작을 구성하지 않는다는 데 합의가 있는 것 같습니다.
그러나 특정 경우에 유의하는 것이 중요합니다. lvalue가 rvalue로 변환되거나 비정적 멤버 함수가 null 포인터로 호출되는 경우와 같은 컨텍스트에서는 정의되지 않은 동작이 발생할 수 있습니다.
결론
결론적으로 널 포인터를 사용하여 정적 멤버에 액세스하는 것은 C에서 본질적으로 정의되지 않은 동작은 아니지만 주의해서 사용해야 합니다. 포인터를 처리할 때 정의되지 않은 동작을 유발할 수 있는 lvalue-rvalue 변환 및 기타 작업의 미묘함을 이해하는 것이 중요합니다.
위 내용은 C 정의되지 않은 동작에서 Null 포인터를 사용하여 정적 멤버에 액세스하고 있습니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!