如何在C中检查变量是否属于某种类型(比较两种类型)?

如何在C中检查变量是否属于某种类型(比较两种类型)?,c,types,struct,C,Types,Struct,在C语言(不是C++/C#)中,如何检查变量是否属于某种类型 例如,类似这样的内容: double doubleVar; if( typeof(doubleVar) == double ) { printf("doubleVar is of type double!"); } 或者更一般:如何比较两种类型,以便compare(double1,double2)将计算为true,而compare(int,double)将计算为false。我还想比较不同组成的结构 基本上,我有一个对类型为“

在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 a”变量做一件事,用“struct b”变量做另一件事。由于C不支持重载,而且
void
指针会丢失其类型信息,因此我需要检查类型。顺便说一句,如果你不能比较类型,那么使用
typeof
操作符有什么意义呢



sizeof方法对我来说似乎是一个实用的解决方案。谢谢你的帮助。我仍然觉得有点奇怪,因为类型在编译时是已知的,但是如果我想象一下我能看到的机器中的进程,为什么信息不是按类型存储的,而是按字节大小存储的。除了地址之外,大小是唯一真正相关的东西。

C不支持这种类型的内省。在C中,你所要求的是不可能的(至少没有编译器特定的扩展;但是在C++中可能是这样的)。 一般来说,使用C时,您需要知道变量的类型。因为每个函数的参数都有具体的类型(我想除了varargs),所以不需要签入函数体。我能看到的唯一剩下的例子是在一个宏体中,而且,C宏并没有那么强大

此外,请注意,C不会在运行时保留任何类型信息。这意味着,即使假设存在类型比较扩展,它也只有在编译时已知类型时才能正常工作(即,测试两个
void*
是否指向相同类型的数据是行不通的)

至于
typeof
:首先,
typeof
是一个GCC扩展。它不是C的标准部分。它通常用于编写只对其参数求值一次的宏,例如(从):

关键字
typeof
允许宏定义一个本地临时变量来保存其参数的值,只允许对其求值一次

简而言之,C不支持重载;您只需创建一个
func_a(结构a*)
func_b(结构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) );
  }
}

当然,您必须记住在创建这些对象时正确初始化标头。

正如其他人所提到的,您不能在运行时提取变量的类型。但是,您可以构造自己的“对象”,并将类型与之一起存储。然后您可以在运行时检查它:

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;
fprintf("%x", variable)

正如其他人已经说过的,这在C语言中是不受支持的。但是,您可以使用
sizeof()
函数检查变量的大小。这可以帮助您确定两个变量是否可以存储相同类型的数据


在此之前,请阅读下面的注释

C是静态类型语言。不能声明对类型a或类型B进行操作的函数,也不能声明保存类型a或类型B的变量。每个变量都有一个显式声明且不可更改的类型,您应该使用这些知识


当您想知道void*是否指向浮点或整数的内存表示时,您必须将此信息存储在其他地方。该语言专门设计为不关心char*是否指向存储为intchar

的内容。目前,在C11中,通过
\u Generic
Generic选择可以获取变量类型。它在编译时工作

语法有点像
开关的语法。这是一个样本(来自):

#定义类型名(x)_泛型((x)\
_Bool:“_Bool”,未签名字符:“未签名字符”\
字符:“字符”,签名字符:“签名字符”\
短整型:“短整型”,无符号短整型:“无符号短整型”\
int:“int”,unsigned int:“unsigned int”\
长整型:“长整型”,无符号长整型:“无符号长整型”\
长整型:“长整型”,无符号长整型:“无符号长整型”\
浮动:“浮动”,双:“双”\
长双精度:“长双精度”,字符*:“指向字符的指针”\
void*:“指向void的指针”,int*:“指向int的指针”\
违约:“其他”)
要实际使用它进行编译时手动类型检查,您可以使用所需的所有类型定义
enum
,如下所示:

double doubleVar;
if( typeof(doubleVar) == double ) {
    printf("doubleVar is of type double!");
}
enum t_typename{
TYPENAME_BOOL,
TYPENAME_UNSIGNED_CHAR,
TYPENAME_CHAR,
TYPENAME\u SIGNED\u CHAR,
TYPENAME\u SHORT\u INT,
TYPENAME\u UNSIGNED\u CHORT\u INT,
TYPENAME_INT,
/* ... */
TYPENAME\u指针\u指向\u INT,
类型名称\其他
};
然后使用
\u Generic
将类型与此
枚举匹配:

#定义类型名(x)_泛型((x)\
_Bool:TYPENAME\u Bool,unsigned char:TYPENAME\u unsigned\u char\
char:TYPENAME\u char,signed char:TYPENAME\u signed\u char\
short int:TYPENAME\u short\u int,无符号short int:TYPENAME\u UNSIGN
double doubleVar;
if(__builtin_types_compatible_p(typeof(doubleVar), double)) {
    printf("doubleVar is of type double!");
}
char s[50];
sprintf(s,"%.2f", yo);
char type=dtype(s);
//Return types are :
//i for integer
//f for float or decimals
//c for character...
/*
 * 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; \
})
#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 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");
}