C语言 如何在 C 中检查变量是否属于某种类型(比较两种类型)?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6280055/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I check if a variable is of a certain type (compare two types) in C?
提问by con-f-use
In C (not C++/C#) how do I check if a variable is of a certain type?
在 C(不是 C++/C#)中,如何检查变量是否属于某种类型?
For example, something like this:
例如,这样的事情:
double doubleVar;
if( typeof(doubleVar) == double ) {
printf("doubleVar is of type double!");
}
Or more general: How do I compare two types so that compare(double1,double2)will evaluate to true, and compare(int,double)will evaluate to false. Also I'd like to compare structs of different composition as well.
或者更一般:我如何比较两种类型,以便compare(double1,double2)评估为真,compare(int,double)评估为假。我也想比较不同组成的结构。
Basically, I have a function that operates on variables of type "struct a" and "struct b". I want to do one thing with the "struct a" variables and the other with the "struct b" variables. Since C doesn't support overloading and the voidpointer losses its type information I need to check for type. BTW, what would be the sense in having a typeofoperator, if you can't compare types?
基本上,我有一个对“struct a”和“struct b”类型的变量进行操作的函数。我想用“struct a”变量做一件事,用“struct b”变量做另一件事。由于 C 不支持重载并且void指针丢失其类型信息,因此我需要检查类型。顺便说一句,typeof如果您无法比较类型,那么拥有运算符有什么意义?
The sizeof method seems to be a practical workaround solution for me. Thanks for your help. I still find it a bit strange since the types are known at compile time, but if I imagine the processes in the machine I can see, why the information is not stored in terms of types, but rather in terms of byte size. Size is the only thing really relevant besides addresses.
sizeof 方法对我来说似乎是一个实用的解决方法。谢谢你的帮助。我还是觉得有点奇怪,因为类型在编译时是已知的,但是如果我想象一下我可以看到的机器中的进程,为什么信息不是按照类型存储的,而是按照字节大小存储的。除了地址之外,大小是唯一真正相关的东西。
采纳答案by Mints97
Getting the type of a variable is, as of now, possible in C11 with the _Genericgeneric selection. It works at compile-time.
到目前为止,在 C11 中可以使用_Generic泛型选择来获取变量的类型。它在编译时工作。
The syntaxis is a bit like switch. Here's a sample (from this answer):
语法有点像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")
To actually use it for compile-time manual type checking, you can define an enumwith all of the types you expect, something like this:
要实际使用它进行编译时手动类型检查,您可以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
};
And then use _Genericto match types to this enum:
然后用于_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)
回答by bdonlan
C does not support this form of type introspection. What you are asking is not possible in C (at least without compiler-specific extensions; it would be possible in C++, however).
C 不支持这种形式的类型自省。您所要求的在 C 中是不可能的(至少没有特定于编译器的扩展;但是在 C++ 中是可能的)。
In general, with C you're expected to know the types of your variable. Since every function has concrete types for its parameters (except for varargs, I suppose), you don't need to check in the function body. The only remaining case I can see is in a macro body, and, well, C macros aren't really all that powerful.
通常,使用 C,您应该知道变量的类型。由于每个函数的参数都有具体的类型(我想除了 varargs),你不需要检查函数体。我能看到的唯一剩下的情况是在宏体中,而且,C 宏并不是那么强大。
Further, note that C does not retain any type information into runtime. This means that, even if, hypothetically, there was a type comparison extension, it would only work properly when the types are known at compile time (ie, it wouldn't work to test whether two void *point to the same type of data).
此外,请注意 C 不会在运行时保留任何类型信息。这意味着,即使假设存在类型比较扩展,它也只有在编译时已知类型时才能正常工作(即,无法测试两个是否void *指向相同类型的数据)。
As for typeof: First, typeofis a GCC extension. It is not a standard part of C. It's typically used to write macros that only evaluate their arguments once, eg (from the GCC manual):
至于typeof: 首先typeof是GCC扩展。它不是 C 的标准部分。它通常用于编写只评估一次参数的宏,例如(来自GCC 手册):
#define max(a,b) \
({ typeof (a) _a = (a); \
typeof (b) _b = (b); \
_a > _b ? _a : _b; })
The typeofkeyword lets the macro define a local temporary to save the values of its arguments, allowing them to be evaluated only once.
该typeof关键字让宏定义本地临时保存其参数值,允许他们只计算一次。
In short, C does not support overloading; you'll just have to make a func_a(struct a *)and func_b(struct b *), and call the correct one. Alternately, you could make your own introspection system:
总之,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) );
}
}
You must, of course, remember to initialize the header properly when creating these objects.
当然,您必须记住在创建这些对象时正确初始化标头。
回答by Steve Walsh
As other people have already said this isn't supported in the C language. You could however check the size of a variable using the sizeof()function. This may help you determine if two variables can store the same type of data.
正如其他人已经说过的,这在 C 语言中不受支持。但是,您可以使用该sizeof()函数检查变量的大小。这可以帮助您确定两个变量是否可以存储相同类型的数据。
Before you do that, read the comments below.
在你这样做之前,请阅读下面的评论。
回答by Mark Wilkins
As others have mentioned, you can't extract the type of a variable at runtime. However, you could construct your own "object" and store the type along with it. Then you would be able to check it at runtime:
正如其他人所提到的,您无法在运行时提取变量的类型。但是,您可以构建自己的“对象”并将类型与其一起存储。然后你就可以在运行时检查它:
typedef struct {
int type; // or this could be an enumeration
union {
double d;
int i;
} u;
} CheesyObject;
Then set the type as needed in the code:
然后在代码中根据需要设置类型:
CheesyObject o;
o.type = 1; // or better as some define, enum value...
o.u.d = 3.14159;
回答by juppman
Gnu GCC has a builtin function for comparing types __builtin_types_compatible_p.
Gnu GCC 有一个用于比较类型的内置函数__builtin_types_compatible_p。
https://gcc.gnu.org/onlinedocs/gcc-3.4.5/gcc/Other-Builtins.html
https://gcc.gnu.org/onlinedocs/gcc-3.4.5/gcc/Other-Builtins.html
This built-in function returns 1 if the unqualified versions of the types type1 and type2 (which are types, not expressions) are compatible, 0 otherwise. The result of this built-in function can be used in integer constant expressions.
This built-in function ignores top level qualifiers (e.g., const, volatile). For example, int is equivalent to const int.
如果类型 type1 和 type2(它们是类型,不是表达式)的非限定版本兼容,则此内置函数返回 1,否则返回 0。此内置函数的结果可用于整数常量表达式。
这个内置函数忽略顶级限定符(例如,const、volatile)。例如,int 等价于 const int。
Used in your example:
在您的示例中使用:
double doubleVar;
if(__builtin_types_compatible_p(typeof(doubleVar), double)) {
printf("doubleVar is of type double!");
}
回答by Green Tree
From linux/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; \
})
Hereyou can find explanation which statements from standard and which GNU extensions above code uses.
在这里,您可以找到对代码使用的标准语句和 GNU 扩展的解释。
(Maybe a bit not in scope of the question, since question is not about failure on type mismatch, but anyway, leaving it here).
(也许有点不在问题的范围内,因为问题不是关于类型不匹配的失败,但无论如何,把它留在这里)。
回答by Daniel Peirano
This is crazily stupid, but if you use the code:
这是非常愚蠢的,但如果你使用代码:
fprintf("%x", variable)
and you use the -Wall flag while compiling, then gcc will kick out a warning of that it expects an argument of 'unsigned int' while the argument is of type '____'. (If this warning doesn't appear, then your variable is of type 'unsigned int'.)
并且您在编译时使用 -Wall 标志,然后 gcc 将发出警告,提示它需要一个 'unsigned int' 的参数,而该参数的类型为 '____'。(如果未出现此警告,则您的变量的类型为“unsigned int”。)
Best of luck!
祝你好运!
Edit:As was brought up below, this only applies to compile time. Very helpful when trying to figure out why your pointers aren't behaving, but not very useful if needed during run time.
编辑:正如下面提到的,这仅适用于编译时。在尝试找出指针不工作的原因时非常有用,但如果在运行时需要,则不是很有用。
回答by Saeed Baig
As another answer mentioned, you can now do this in C11 with _Generic.
正如提到的另一个答案,您现在可以在 C11 中使用_Generic.
For example, here's a macro that will check if some input is compatible with another type:
例如,这里有一个宏,用于检查某些输入是否与另一种类型兼容:
#include <stdbool.h>
#define isCompatible(x, type) _Generic(x, type: true, default: false)
You can use the macro like so:
您可以像这样使用宏:
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
}
This can also be used on other types, including structs. E.g.
这也可以用于其他类型,包括结构。例如
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;
}
And on typedefs.
在 typedef 上。
typedef char* string;
string greeting = "Hello world!";
if (isCompatible(greeting, string)) {
printf("Can check typedefs.\n");
}
However, it doesn't always give you the answer you expect. For instance, it can't distinguish between an array and a pointer.
然而,它并不总是给你你期望的答案。例如,它无法区分数组和指针。
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");
}
Answer borrowed from here: http://www.robertgamble.net/2012/01/c11-generic-selections.html
从这里借用的答案:http: //www.robertgamble.net/2012/01/c11-generic-selections.html
回答by Subham Debnath
For that purpose I have written a simple C program for that... It is in github...GitHub Link
为此,我为此编写了一个简单的 C 程序……它在 github 中…… GitHub 链接
Here how it works... First convert your double into a char string named s..
这里是如何工作的......首先将你的双精度转换为一个名为 s..
char s[50];
sprintf(s,"%.2f", yo);
Then use my dtypefunction to determine the type...
My function will return a single character...You can use it like this...
然后用我的dtype函数来判断类型……我的函数会返回单个字符……你可以这样使用……
char type=dtype(s);
//Return types are :
//i for integer
//f for float or decimals
//c for character...
Then you can use comparison to check it... That's it...
然后你就可以用比较来检查了……就是这样……
回答by blaze
C is statically typed language. You can't declare a function which operate on type A or type B, and you can't declare variable which hold type A or type B. Every variable has an explicitly declared and unchangeable type, and you supposed to use this knowledge.
C 是静态类型语言。您不能声明对类型 A 或类型 B 进行操作的函数,也不能声明持有类型 A 或类型 B 的变量。每个变量都有一个显式声明且不可更改的类型,您应该使用这些知识。
And when you want to know if void *points to memory representation of float or integer - you have to store this information somewhere else. The language is specifically designed not to care if char *points to something stored as intor char.
当您想知道void * 是否指向浮点数或整数的内存表示时 - 您必须将此信息存储在其他地方。该语言专门设计为不关心char * 是否指向存储为int或char 的内容。

