C에서 불완전한 유형 오류에 대한 역참조 포인터

Jay Shaw 2023년10월12일
  1. C에서 불완전한 유형에 대한 역참조 포인터 오류의 원인
  2. C의 불완전한 유형
  3. C에서 포인터 참조 및 역참조
  4. C에서 불완전한 유형에 대한 역참조 포인터 오류 해결
  5. 결론
C에서 불완전한 유형 오류에 대한 역참조 포인터

포인터는 변수 내부에 저장된 값의 주소를 저장하는 데 사용되는 것으로 알려져 있습니다. 이 포인터 변수는 주소를 얻기 위해 변수를 참조하거나 값에 액세스하기 위해 역참조할 수 있습니다.

그러나 이 포인터를 보거나 편집해야 하는 경우 역참조해야 합니다. 이 역참조가 선언되었지만 정의되지 않은 유형을 통해 수행되면 불완전한 유형에 대한 역참조 포인터 오류가 발생합니다.

C에서 불완전한 유형에 대한 역참조 포인터 오류의 원인

이 오류는 컴파일러가 구조체로 역참조되는 포인터를 발견할 때 발생합니다. 컴파일러가 구조체 쪽으로 이동하면 구조체가 불완전한 것, 즉 제대로 정의되지 않은 것을 발견합니다.

컴파일러는 정의되지 않은 구조체가 포인터를 참조하기 위해 호출될 때 다른 오류를 발생시킵니다. 발생한 오류 유형은 사용된 컴파일러에 따라 다릅니다.

GCC 컴파일러의 불완전한 유형에 대한 역참조 포인터 오류

예를 들어 정의되지 않은 구조체는 다음과 같습니다.

struct circle {
  int length;
};
int main() {
  struct round *x = 0;
  *x;
}

위의 C 프로그램에서 circle 구조체가 구성되어 있지만 main 함수 내부에서 호출되는 구조체의 이름은 round입니다.

main 함수 내에서 객체 포인터 *x는 구조체 round에서 생성됩니다. 마지막으로 포인터 개체가 호출됩니다.

여기서 불완전한 구조체는 마치 완전한 구조체인 것처럼 사용되어 컴파일러에서 오류를 발생시킵니다.

1035906452/source.c: In function 'main':
1035906452/source.c:6:5: error: dereferencing pointer to incomplete type 'struct round'
     *x;
     ^~

컴파일러가 불완전한 형식에 대한 역참조 포인터 오류를 발생시키는 것을 관찰할 수 있습니다.

일반적으로 C는 입력된 구조체의 이름을 찾습니다. 원래 구조체를 찾을 수 없으면 일반적으로 이 구조체가 나타납니다. 해당 포인터를 가리키는 포인터를 가리키면 나타납니다.

이 오류는 일반적으로 구조체 이름이 코드의 구조체 초기화와 다른 경우에 나타납니다.

구조체는 또한 컴파일러가 읽을 수 없는 별칭이 주어지면 오류를 발생시킬 수 있지만 모든 컴파일러에서 발생하지는 않습니다.

Clang 컴파일러의 불완전한 유형에 대한 역참조 포인터 오류

이는 동일한 코드가 Clang 컴파일러를 통해 실행될 때 발생합니다.

1790191360/source.c:6:5: error: incomplete type 'struct round' where a complete type is required
    *x;
    ^
1790191360/source.c:5:12: note: forward declaration of 'struct round'
    struct round *x = 0;
           ^
1790191360/source.c:6:5: warning: expression result unused [-Wunused-value]
    *x;
    ^~
1 warning and 1 error generated.

여기서 컴파일러는 불완전한 구조체를 호출하지만 참조되지 않은 포인터는 오류 대신 경고로 남겨둡니다.

불완전한 유형에 대한 역참조 포인터 오류가 발생하는 이유를 이해하려면 두 가지 개념을 알아야 합니다.

  1. 불완전한 유형이란 무엇입니까?
  2. 포인터 역참조란 무엇을 의미합니까?

C의 불완전한 유형

선언되었지만 지정되지 않은 유형은 불완전합니다(구조체 유형의 경우).

컴파일러가 한 이름을 다른 이름과 일치시키지 못하게 하는 유형 이름의 오타는 C 언어에서 불완전한 유형 오류의 일반적인 원인입니다(예: 선언을 정의에 일치시키는 경우).

불완전한 유형이 누락된 유형이라고 생각하는 것은 오해입니다. 불완전한 유형은 구조체 외부에서도 발생할 수 있습니다.

세 가지 시나리오로 인해 불완전한 유형이 발생합니다.

  1. 멤버가 없는 구조체 유형.
  2. 멤버가 없는 유니온 타입.
  3. 선언되었지만 요소가 삽입되지 않은 배열.

불완전한 유형 생성 및 정의

불완전한 유형을 완성하기 위해서는 유사한 구조체 또는 유형이 부족한 정보로 지정되어야 합니다.

불완전한 유형의 생성 및 완성은 아래 예에서 설명됩니다.

구조 유형을 선언하지만 멤버를 생략하여 불완전한 구조 유형을 생성합니다. 이 그림에서 x 포인터는 라이브러리라는 불완전한 구조 유형을 가리킵니다.

struct library *x;

불완전한 구조 유형을 완성하기 위해 제공된 멤버와 함께 나중에 동일한 범위에서 동일한 구조 유형을 선언합니다.

struct library {
  int book_id;
  char book_name[50];
}

불완전한 유형의 배열을 만들려면 반복 횟수를 지정하지 않고 배열 유형을 선언합니다. 예를 들어:

char book_name[]; /* book_name has incomplete type */

불완전한 배열 유형을 완료하도록 반복 횟수가 설정된 동일한 범위에서 나중에 동일한 이름을 선언합니다.

char book_name[25]; /* book_name now has complete type */

불완전한 유형이 완성되는 방법을 이해했으면 불완전한 유형에 대한 역참조 포인터 오류를 해결하는 두 번째 부분으로 이동할 수 있습니다.

C에서 포인터 참조 및 역참조

포인터의 기능은 값의 주소를 저장하는 것입니다. 즉, 무언가에 대한 참조를 저장한다는 의미입니다. 포인터가 가리키는 객체를 포인티라고 합니다.

C에서 포인터 참조

포인터와 포인터가 가리키는 포인티를 할당하는 데는 두 가지 단계가 있습니다. 포인터/포인티 구조는 두 가지 수준의 작동을 갖는 것으로 생각할 수 있습니다.

작동하려면 두 수준에서 모든 것이 설정되어야 합니다. 가장 빈번한 실수는 포인터 수준을 설정하는 것을 무시하면서 포인터 수준을 조작하는 코드를 작성하는 데 집중하는 것입니다.

포인터에 접촉하지 않는 포인터 작업은 때때로 “얕은” 작업이라고 하며 접촉하는 작업은 “깊은” 작업이라고 합니다.

다음 코드를 고려하십시오.

포인터 ptr_amain 함수 내부에 생성됩니다. 이 포인터는 생성되지만 pointee 또는 메모리 청크가 할당되지 않으면 무언가를 저장할 수 없습니다.

메모리 할당은 malloc에 의해 수행되며 주어진 크기는 데이터 유형 int와 동일합니다.

void main() {
  int* ptr_a;  // Allocate the pointer

  ptr_a = malloc(
      sizeof(int));  // Allocate an int pointee, and set ptr_a to point to it
}

C++ 코드:

int main() {
  int* ptr_a;  // Allocate the pointer ptr_a

  ptr_a = new int;  // Allocate an int pointee, and set ptr_a to point to it
}

C에서 포인터 역참조

역참조 연산은 포인터에서 시작하여 포인티까지 이어집니다. 목표는 pointee 상태를 검사하거나 수정하는 것일 수 있습니다.

포인터는 포인티가 있는 경우에만 역참조할 수 있습니다. 포인터가 자신을 가리키도록 만들기 전에 pointee도 할당되어야 합니다. 포인터 설정을 잊는 것은 포인터 프로그램에서 가장 자주 범하는 실수입니다.

코드에서 포인터를 성공적으로 역참조하지 못하는 것은 가장 일반적인 런타임 충돌입니다. Java의 런타임 시스템은 사소한 경고와 함께 부적절한 역참조 문제에 플래그를 지정합니다.

C 및 C++와 같은 컴파일된 언어에서 잘못된 역참조로 인해 충돌이 발생하거나 자발적인 메모리 손상이 발생할 수 있습니다. 이로 인해 컴파일된 언어에서 포인터 문제를 찾기가 어렵습니다.

C 코드:

메모리가 할당되고 포인터 ptr_a를 가리키면 이를 역참조하여 값이 내부에 저장됩니다.

void main() {
  int* ptr_a;

  ptr_a = malloc(
      sizeof(int));  // Allocate an int pointee, and set ptr_a to point to it

  *ptr_a = 42;  // Dereference ptr_a to store 42 in its pointee
}

C++ 코드:

int main() {
  int* ptr_a;  // Allocate the pointers

  ptr_a = new int;  // Allocate an int pointee, and set ptr_a to point to it

  *ptr_a = 42;  // Dereference ptr_a to store 42 in its pointee
}

C의 공유 포인터

두 개의 포인터가 동일한 포인트에 지정되면 둘 다 그곳을 가리킵니다. 결과적으로 yy = x일 때 x와 동일한 포인트를 가리킵니다.

포인트는 포인터 할당의 영향을 받지 않습니다.

다른 포인터와 동일한 참조를 공유하도록 하나의 포인터만 수정합니다. 포인터 할당 후 두 포인터는 포인티를 “공유"하는 것으로 간주됩니다.

C 코드:

void main() {
  int* ptr_a;
  int* ptr_b;

  ptr_a = malloc(sizeof(int));

  *ptr_a = 42;

  *ptr_b = 13;  // CRASH -- ptr_b does not have a pointee yet

  ptr_b = ptr_a;  // Pointer assignment sets ptr_b to point to ptr_a's pointee

  *ptr_b = 13;  // Dereference ptr_b to store 13 in its (shared) pointee
}

우리는 불완전한 유형에 대한 역참조 포인터 오류를 해결하는 두 가지 개념을 이해했습니다. 이제 오류가 발생한 코드와 문제 해결 방법을 살펴보겠습니다.

C에서 불완전한 유형에 대한 역참조 포인터 오류 해결

아래 프로그램에는 정수 멤버 length가 있는 rectangle 구조체가 있습니다. 구조체의 이름은 불완전한 유형을 만들기 위해 의도적으로 main 함수 내부의 이름과 다르게 만들어집니다.

main 함수 내에서 포인터 *a가 생성되고 rectangle 구조체 크기의 메모리를 할당한 다음 이를 향합니다.

그런 다음 포인터는 그 안에 값을 저장하기 위해 구조체 멤버 length를 역참조하는 데 사용됩니다. 구조체는 불완전한 유형이므로 불완전한 유형에 대한 역참조 포인터 오류를 발생시켜야 합니다.

#include <stdio.h>
#include <stdlib.h>

struct rectangle {
  int length;
};

int main() {
  struct square *a;
  a = (struct rectngle *)malloc(sizeof(struct rectngle));
  a->length = 33;
  printf("%d", *a);
}

출력:

1647679200/source.c: In function 'main':
1647679200/source.c:10:38: error: invalid application of 'sizeof' to incomplete type 'struct rectngle'
  a = (struct rectngle*)malloc(sizeof(struct rectngle));
                                      ^~~~~~
1647679200/source.c:11:3: error: dereferencing pointer to incomplete type 'struct square'
  a->length = 33;
   ^~

이 문제를 해결하려면 불완전한 유형을 완료해야 합니다. 이 경우 구조체 rectngle입니다.

불완전한 구조체를 완성하고 main 함수 내부의 포인터를 통해 해당 멤버를 역참조하려면 이러한 변경을 수행해야 합니다.

#include <stdio.h>
#include <stdlib.h>

struct rectangle {  // a struct rectngle is created
  int length;
};

int main() {
  struct rectangle *a;  // name of struct inside main() is same as above struct

  a = (struct rectangle *)malloc(sizeof(
      struct rectangle)); /*pointer allocated memory and
                                                                   pointer
                             to pointer 'a'.   */

  a->length = 33;  // pointer deferenced.

  printf("%d", *a);  // value of pointer dereferenced
}

출력:

33

결론

이 문서에서는 불완전한 형식에 대한 역참조 포인터로 인해 발생하는 오류에 대해 설명합니다. 이 기사를 읽은 후 독자는 포인터와 완전한 불완전한 유형을 쉽게 참조하고 참조할 수 있습니다.

관련 문장 - C Error