C에서 변수가 특정 유형(두 유형 비교)인지 어떻게 확인합니까?
C(C++/C# 아님)에서 변수가 특정 유형인지 어떻게 확인합니까?
예를 들면 다음과 같습니다.
double doubleVar;
if( typeof(doubleVar) == double ) {
printf("doubleVar is of type double!");
}
또는 더 일반적으로: compare(double1,double2)
true로 compare(int,double)
평가되고 false로 평가 되도록 두 유형을 어떻게 비교합니까? 또한 다른 구성의 구조체도 비교하고 싶습니다.
기본적으로 "struct a" 및 "struct b" 유형의 변수에 대해 작동하는 함수가 있습니다. "struct" 변수로 한 가지 작업을 수행하고 "struct b" 변수로 다른 작업을 수행하고 싶습니다. C는 오버로딩을 지원하지 않고 void
포인터가 유형 정보를 잃어버리기 때문에 유형을 확인해야 합니다. BTW, typeof
유형을 비교할 수 없다면 연산자 를 갖는 것이 의미가 있습니까?
sizeof 메서드는 저에게 실용적인 해결 방법인 것 같습니다. 당신의 도움을 주셔서 감사합니다. 컴파일 시간에 유형이 알려져 있기 때문에 여전히 약간 이상하지만 시스템의 프로세스를 상상해 보면 정보가 유형 측면에서 저장되지 않고 바이트 크기 측면에서 저장되는 이유를 알 수 있습니다. 크기는 주소 외에 실제로 관련이 있는 유일한 것입니다.
변수 유형을 가져오는 것은 현재 C11에서 _Generic
일반 선택이 가능합니다. 컴파일 타임에 작동합니다.
구문은 약간 switch
. 다음은 이 답변 의 샘플입니다 .
#define typename(x) _Generic((x), \
_Bool: "_Bool", unsigned char: "unsigned char", \
char: "char", signed char: "signed char", \
short int: "short int", unsigned short int: "unsigned short int", \
int: "int", unsigned int: "unsigned int", \
long int: "long int", unsigned long int: "unsigned long int", \
long long int: "long long int", unsigned long long int: "unsigned long long int", \
float: "float", double: "double", \
long double: "long double", char *: "pointer to char", \
void *: "pointer to void", int *: "pointer to int", \
default: "other")
컴파일 타임 수동 유형 검사에 실제로 사용하려면 enum
다음과 같이 예상하는 모든 유형으로 정의할 수 있습니다 .
enum t_typename {
TYPENAME_BOOL,
TYPENAME_UNSIGNED_CHAR,
TYPENAME_CHAR,
TYPENAME_SIGNED_CHAR,
TYPENAME_SHORT_INT,
TYPENAME_UNSIGNED_CHORT_INT,
TYPENAME_INT,
/* ... */
TYPENAME_POINTER_TO_INT,
TYPENAME_OTHER
};
그런 다음 _Generic
유형을 다음과 일치시키는 데 사용 하십시오 enum
.
#define typename(x) _Generic((x), \
_Bool: TYPENAME_BOOL, unsigned char: TYPENAME_UNSIGNED_CHAR, \
char: TYPENAME_CHAR, signed char: TYPENAME_SIGNED_CHAR, \
short int: TYPENAME_SHORT_INT, unsigned short int: TYPENAME_UNSIGNED_SHORT_INT, \
int: TYPENAME_INT, \
/* ... */ \
int *: TYPENAME_POINTER_TO_INT, \
default: TYPENAME_OTHER)
C는 이러한 형식의 내부 검사를 지원하지 않습니다. 당신이 묻는 것은 C에서는 불가능합니다(적어도 컴파일러 관련 확장 없이는 가능하지만 C++에서는 가능합니다).
일반적으로 C를 사용하면 변수의 유형을 알아야 합니다. 모든 함수에는 매개변수에 대한 구체적인 유형이 있으므로(내 생각에 varargs 제외) 함수 본문을 체크인할 필요가 없습니다. 내가 볼 수 있는 유일한 남아 있는 경우는 매크로 본문이고, 글쎄요, C 매크로는 그다지 강력하지 않습니다.
또한 C는 런타임에 유형 정보를 유지하지 않습니다. 이는 가설적으로 유형 비교 확장이 있더라도 컴파일 시간에 유형이 알려진 경우에만 제대로 작동한다는 것을 의미합니다(즉, 두 개의 void *
데이터가 동일한 유형의 데이터를 가리키는 지 여부를 테스트하는 것은 작동하지 않음 ).
에 관해서 typeof
: 첫째, typeof
GCC 확장입니다. C의 표준 부분이 아닙니다. 일반적으로 인수를 한 번만 평가하는 매크로를 작성하는 데 사용됩니다(예: ( GCC 매뉴얼에서 ):
#define max(a,b) \
({ typeof (a) _a = (a); \
typeof (b) _b = (b); \
_a > _b ? _a : _b; })
이 typeof
키워드를 사용하면 매크로가 인수 값을 저장하기 위해 로컬 임시를 정의하여 한 번만 평가할 수 있습니다.
간단히 말해서 C는 오버로딩을 지원하지 않습니다. func_a(struct a *)
and 를 만들고 func_b(struct b *)
올바른 것을 호출하기만 하면 됩니다. 또는 다음과 같이 자신만의 내성 시스템을 만들 수 있습니다.
struct my_header {
int type;
};
#define TYPE_A 0
#define TYPE_B 1
struct a {
struct my_header header;
/* ... */
};
struct b {
struct my_header header;
/* ... */
};
void func_a(struct a *p);
void func_b(struct b *p);
void func_switch(struct my_header *head);
#define func(p) func_switch( &(p)->header )
void func_switch(struct my_header *head) {
switch (head->type) {
case TYPE_A: func_a((struct a *)head); break;
case TYPE_B: func_b((struct b *)head); break;
default: assert( ("UNREACHABLE", 0) );
}
}
물론 이러한 객체를 생성할 때 헤더를 올바르게 초기화하는 것을 기억해야 합니다.
다른 사람들이 이미 말했듯이 이것은 C 언어에서 지원되지 않습니다. 그러나 sizeof()
함수를 사용하여 변수의 크기를 확인할 수 있습니다. 이렇게 하면 두 변수가 동일한 유형의 데이터를 저장할 수 있는지 확인하는 데 도움이 될 수 있습니다.
그렇게 하기 전에 아래 주석을 읽으십시오 .
다른 사람들이 언급했듯이 런타임에 변수 유형을 추출할 수 없습니다. 그러나 고유한 "객체"를 구성하고 유형을 함께 저장할 수 있습니다. 그런 다음 런타임에 확인할 수 있습니다.
typedef struct {
int type; // or this could be an enumeration
union {
double d;
int i;
} u;
} CheesyObject;
그런 다음 코드에서 필요에 따라 유형을 설정합니다.
CheesyObject o;
o.type = 1; // or better as some define, enum value...
o.u.d = 3.14159;
Gnu GCC에는 유형 비교를 위한 내장 함수가 있습니다 __builtin_types_compatible_p
.
https://gcc.gnu.org/onlinedocs/gcc-3.4.5/gcc/Other-Builtins.html
이 내장 함수는 type1 및 type2(표현식이 아닌 유형임)의 규정되지 않은 버전이 호환되는 경우 1을 반환하고 그렇지 않으면 0을 반환합니다. 이 내장 함수의 결과는 정수 상수 표현식에서 사용할 수 있습니다.
이 내장 함수는 최상위 한정자(예: const, volatile)를 무시합니다. 예를 들어 int는 const int와 동일합니다.
귀하의 예에서 사용:
double doubleVar;
if(__builtin_types_compatible_p(typeof(doubleVar), double)) {
printf("doubleVar is of type double!");
}
이것은 미친 짓이지만 코드를 사용하면 다음과 같습니다.
fprintf("%x", variable)
컴파일하는 동안 -Wall 플래그를 사용하면 gcc는 인수가 '____' 유형인 동안 'unsigned int' 인수를 예상한다는 경고를 표시합니다. (이 경고가 나타나지 않으면 변수가 'unsigned int' 유형인 것입니다.)
행운을 빕니다!
편집: 아래에서 언급했듯이 이것은 컴파일 시간에만 적용됩니다. 포인터가 작동하지 않는 이유를 알아내려고 할 때 매우 유용하지만 런타임 중에 필요한 경우에는 그다지 유용하지 않습니다.
에서 리눅스 / typecheck.h :
/*
* Check at compile time that something is of a particular type.
* Always evaluates to 1 so you may use it easily in comparisons.
*/
#define typecheck(type,x) \
({ type __dummy; \
typeof(x) __dummy2; \
(void)(&__dummy == &__dummy2); \
1; \
})
여기 에서 표준의 명령문과 코드 위의 GNU 확장이 사용하는 설명을 찾을 수 있습니다.
(질문이 유형 불일치에 대한 실패에 관한 것이 아니라 어쨌든 여기에 남겨두기 때문에 질문의 범위에 약간 없을 수도 있습니다.)
다른 답변에서 언급했듯이 이제 C11에서 _Generic
.
예를 들어 다음은 일부 입력이 다른 유형과 호환되는지 확인하는 매크로입니다.
#include <stdbool.h>
#define isCompatible(x, type) _Generic(x, type: true, default: false)
다음과 같이 매크로를 사용할 수 있습니다.
double doubleVar;
if (isCompatible(doubleVar, double)) {
printf("doubleVar is of type double!\n"); // prints
}
int intVar;
if (isCompatible(intVar, double)) {
printf("intVar is compatible with double too!\n"); // doesn't print
}
이것은 구조체를 포함한 다른 유형에서도 사용할 수 있습니다. 예
struct A {
int x;
int y;
};
struct B {
double a;
double b;
};
int main(void)
{
struct A AVar = {4, 2};
struct B BVar = {4.2, 5.6};
if (isCompatible(AVar, struct A)) {
printf("Works on user-defined types!\n"); // prints
}
if (isCompatible(BVar, struct A)) {
printf("And can differentiate between them too!\n"); // doesn't print
}
return 0;
}
그리고 typedef에서.
typedef char* string;
string greeting = "Hello world!";
if (isCompatible(greeting, string)) {
printf("Can check typedefs.\n");
}
그러나 항상 기대하는 답변을 제공하지는 않습니다. 예를 들어 배열과 포인터를 구분할 수 없습니다.
int intArray[] = {4, -9, 42, 3};
if (isCompatible(intArray, int*)) {
printf("Treats arrays like pointers.\n");
}
// The code below doesn't print, even though you'd think it would
if (isCompatible(intArray, int[4])) {
printf("But at least this works.\n");
}
여기에서 빌린 답변: http://www.robertgamble.net/2012/01/c11-generic-selections.html
C는 정적으로 유형이 지정된 언어입니다. A형이나 B형에 대해 동작하는 함수는 선언할 수 없고, A형이나 B형을 가지는 변수는 선언할 수 없습니다. 모든 변수에는 명시적으로 선언되고 변경할 수 없는 형이 있으므로, 이 지식을 사용해야 합니다.
그리고 void * 가 float 또는 integer의 메모리 표현을 가리키는지 알고 싶을 때 이 정보를 다른 곳에 저장해야 합니다. 언어는 char * 이 int 또는 char 로 저장된 항목을 가리키는지 여부를 신경 쓰지 않도록 특별히 설계되었습니다 .
이를 위해 간단한 C 프로그램을 작성했습니다... github에 있습니다... GitHub Link
작동 원리는... 먼저 double을 s..라는 char 문자열로 변환합니다.
char s[50];
sprintf(s,"%.2f", yo);
그런 다음 내 dtype
함수를 사용하여 유형을 결정합니다... 내 함수는 단일 문자를 반환합니다... 이렇게 사용할 수 있습니다...
char type=dtype(s);
//Return types are :
//i for integer
//f for float or decimals
//c for character...
그런 다음 비교를 사용하여 확인할 수 있습니다. 그게 다야...
ReferenceURL : https://stackoverflow.com/questions/6280055/how-do-i-check-if-a-variable-is-of-a-certain-type-compare-two-types-in-c
'IT이야기' 카테고리의 다른 글
SQL Server 2008에서 트랜잭션 로그를 보는 방법 (0) | 2021.10.14 |
---|---|
동일한 키로 여러 사전을 병합하는 방법 (0) | 2021.10.14 |
Django - FileField가 없는지 확인 (0) | 2021.10.13 |
항아리 안의 참조 항아리 (0) | 2021.10.13 |
armv7이란 (0) | 2021.10.13 |