void 포인터 (void *)가 두 가지 데이터 유형 중 하나인지 확인하는 방법은 무엇입니까?


10

2 type초의 매개 변수 를 허용하려는 함수를 작성 중입니다.

  • A string(char *)
  • structuren 개의 요소가있는 A.

그리고 이것을 달성하기 위해 void *매개 변수 유형 으로 간단한 것을 사용할 생각입니다 . 그러나 매개 변수가 하나의 유형인지 다른 유형인지 안전하게 확인하는 방법을 모르겠습니다.


10
당신은 할 수 없습니다! 최소한 함수에 void*포인트를 나타내는 두 번째 매개 변수를 추가해야 합니다.
Adrian Mole

4
어쨌든 두 번째 매개 변수를 추가해야하는 경우 ... 그리고, 당신은 단지뿐만 아니라 두 개의 별도의 기능을 쓸 수 func_strfunc_struct및 컴파일 타임에 유형 검사를 얻을.
M Oehm

그렇기 때문에 한 가지 기능만으로 가능하다고 생각한 것입니다.
localhost

1
안전하고 휴대 가능한 방법으로는 불가능합니다. 당신이 충분히 용감하다면 휴리스틱을 사용하여 메모리의 첫 바이트가 문자에 대해 기대할 수있는 것처럼 보일지 추측 할 수는 있지만 안전하다고 부를 수는 없습니다 .
Ballesta Serge

문자열 및 구조체 함수의 공통 이름을 원한다면 _Generic매크로를 사용할 수 있습니다 . 태그지정된 union 등으로 자체 식별 유형을 만들 수도 있습니다 char *. 이는 원시 문자열을 전달할 수 없음을 의미 합니다. 가치가있는 것보다 더 큰 문제 일 것입니다.
M Oehm

답변:


12

번역 void*
"친애하는 컴파일러, 이것은 포인터이며, 이에 대한 추가 정보는 없습니다."입니다.

일반적으로 컴파일러는 이전에 얻은 정보로 여전히 기억하고 잊어 버렸을 수 있기 때문에 프로그래머보다 더 잘 알고 있습니다.
그러나이 특별한 경우에, 당신은 더 잘 알거나 더 잘 알아야합니다. void*정보 의 모든 경우에 다른 방법으로 이용할 수 있지만 "알아야하는"프로그래머 만 사용할 수 있습니다. 프로그래머는 정보를 컴파일러에 제공해야합니다. 또는 실행중인 프로그램에 더 좋습니다. 한 가지 장점 void*은 정보가 런타임 중에 변경 될 수 있기 때문 입니다.
일반적으로 이는 추가 매개 변수를 통해 정보를 함수에, 때로는 컨텍스트를 통해 (예 : "알아야하는"프로그램) 제공합니다 (예 : 가능한 각 유형마다 별도의 함수가 있으며, 함수는 형식을 의미합니다).

결국 void*에는 정보 유형이 포함되지 않습니다.
많은 프로그래머들이 이것을 "유형 정보를 알 필요가 없습니다"라고 오해합니다.
그러나 그 반대의 경우에, 사용 하면 타입 정보를 추적하고 적절하게 프로그램 / 컴파일러에 제공하는 프로그래머의 책임 이 void* 증가 합니다.


또한 컴파일러는 실제로 지적 된 데이터 유형이 무엇인지 알고 있습니다. 따라서 어떤 void*함수 로 뛰어 들어서 잘못된 유형으로 캐스팅 한 다음 데이터를 참조 해제하면 모든 방식의 정의되지 않은 동작이 호출됩니다.
Lundin

5

void*일반적인 프로그래밍에서는 더 이상 사용되지 않지만 요즘에는 사용해야 할 상황이 많지 않습니다. 존재하지 않는 유형의 안전으로 이어지기 때문에 위험합니다. 그리고 언급했듯이 유형 정보도 잃어 버렸습니다. 즉, enum과 함께 번거로운 부분 을 드래그해야 합니다 void*.

대신 _Generic컴파일 타임에 유형을 확인하고 유형 안전을 추가 할 수있는 C11 을 사용해야합니다 . 예:

#include <stdio.h>

typedef struct
{
  int n;
} s_t; // some struct

void func_str (const char* str)
{
  printf("Doing string stuff: %s\n", str);
}

void func_s (const s_t* s)
{
  printf("Doing struct stuff: %d\n", s->n);
}

#define func(x) _Generic((x),              \
  char*: func_str, const char*: func_str,  \
  s_t*:  func_s,   const s_t*:  func_s)(x) \


int main()
{
  char str[] = "I'm a string";
  s_t s = { .n = 123 };

  func(str);
  func(&s); 
}

const지원하려는 모든 유형의 정규화 된 버전 을 제공해야합니다 .


호출자가 잘못된 유형을 전달할 때 더 나은 컴파일러 오류를 원하면 정적 어설 션을 추가 할 수 있습니다.

#define type_check(x) _Static_assert(_Generic((x), \
  char*:   1,  const char*: 1,  \
  s_t*:    1,  const s_t*:  1,  \
  default: 0), #x": incorrect type.")

#define func(x) do{ type_check(x); _Generic((x),     \
  char*: func_str, const char*: func_str,            \
  s_t*:  func_s,   const s_t*:  func_s)(x); }while(0) 

같은 것을 시도 int x; func(x);하면 컴파일러 메시지가 나타납니다 "x: incorrect type".

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.