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


73

在C(不是C ++ / C#)中,如何检查变量是否为某种类型?

例如,如下所示:

或更笼统:我如何比较两种类型,以便compare(double1,double2)评估为true,而compare(int,double)评估为false。我也想比较不同组成的结构。

基本上,我有一个对类型“ struct a”和“ struct b”的变量进行操作的函数。我想用“ struct a”变量做一件事,而用“ struct b”变量做另一件事。由于C不支持重载,并且void指针丢失了其类型信息,因此我需要检查类型。顺便说一句,typeof如果您不能比较类型,那么拥有运算符会有什么意义?


sizeof方法对我来说似乎是一种实际的解决方法。谢谢你的帮助。我仍然发现它有点奇怪,因为类型是在编译时就知道的,但是如果我能想象我可以看到机器中的进程,为什么信息不是按类型存储,而是按字节大小存储。大小是唯一真正有意义的,除了地址。


您不能将它们都转换为double(并添加0.00)吗?不知道这在C语言中是否可行,只是一个建议。
凯文

1
查看源代码,它指出doubleVar是double。不需要(也不可能)在运行时检查它。
Habalusa 2011年

回应Edit#1:您是否考虑过使用函数指针(如vtable)解决问题?
Michael Foukarakis 2011年

如果您喜欢sizeof方法,请阅读有关gcc的tgmath实现的文章
quinmars 2011年

@Michael Foukarakis您能提供一个例子吗?
con-f-use

Answers:


46

到目前为止,在C11中使用_Generic通用选择即可获取变量的类型。它在编译时起作用。

语法有点像switch。这是一个示例(来自此答案):

要将其实际用于编译时手动类型检查,您可以定义enum具有所有期望类型的,如下所示:

然后使用_Generic来匹配类型enum


17

C不支持这种形式的自省形式。您要问的是在C中是不可能的(至少没有编译器特定的扩展;但是在C ++中是可能的)。

通常,使用C,您应该知道变量的类型。由于每个函数的参数都有具体的类型(我想应该是varargs除外),因此您不需要检入函数体。我能看到的唯一剩下的情况是在宏主体中,而且,C宏实际上并没有那么强大。

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

至于typeof:首先,typeof是一个GCC扩展。它不是C的标准部分。通常用于编写仅对它们的参数进行一次评估的宏,例如(来自GCC手册):

typeof关键字让宏定义本地临时保存其参数值,允许他们只计算一次。

简而言之,C不支持重载。您只需制作一个func_a(struct a *)func_b(struct b *),然后调用正确的一个即可。或者,您可以建立自己的自省系统:

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


1
甚至没有解决方法或使用宏或其他东西的巧妙技巧?
混淆使用

2
@ con-f-use,为什么需要这个?
bdonlan

@ con-f-use宏在编译时工作。当您编写代码时,他们和您一样了解。
cnicutar 2011年

@cnicutar我知道什么是宏。谢谢!@bdonlan我几乎不接受您的回答感到很难过。sizeof的想法对我来说只是一个更好的解决方法。+10为你我的朋友,非常感谢。
混淆使用

4
@ con-f-use,这是一个不错的解决方法,直到您添加一个成员,大小变得相等,并且突然间它总是在struct a分支,即使它是一个struct b。:)
bdonlan

13

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

在执行此操作之前,请阅读下面的评论


当我自己想到它时,您就发布了此内容。一定会尝试。
混淆使用

5
此外,如果您坚持要这样做,请添加一个静态断言以确保大小永远不会意外相同:struct STATIC_ASSERT_size_not_equal_s { char STATIC_ASSERT_size_not_equal[sizeof(a) == sizeof(b) ? -1 : 1]; };
bdonlan

在我比较结构的情况下,它们都具有相同的成员,除了一个具有两个额外的双重成员。因此,如果我独立于体系结构或其他因素执行“ if(sizeof(a)> sizeof(b))”,就应该保存下来。无论如何谢谢。
混淆使用

4
“但是,您可以使用sizeof()函数检查变量的大小” sizeof (int) == sizeof (float),但是它们具有完全不同的存储格式。
pho11 2011年

6

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

然后根据需要在代码中设置类型:


6

Gnu GCC具有用于比较类型的内置功能__builtin_types_compatible_p

https://gcc.gnu.org/onlinedocs/gcc-3.4.5/gcc/Other-Builtins.html

如果类型1和类型2(它们是类型,而不是表达式)的非限定版本兼容,则此内置函数返回1,否则返回0。此内置函数的结果可用于整数常量表达式。

此内置函数忽略顶级限定符(例如const,volatile)。例如,int等同于const int。

在您的示例中使用:


4

linux / typecheck.h

在这里,您可以找到解释说明标准中的哪些语句以及上述代码中使用的GNU扩展。

(也许有点不在问题的范围内,因为问题不是关于类型不匹配的失败,而是无论如何,将其留在这里)。


2

这是疯狂的愚蠢,但是如果使用代码:

并且在编译时使用-Wall标志,则gcc将发出警告,提示它期望参数为'____'类型的参数为'unsigned int'。(如果未出现此警告,则您的变量的类型为'unsigned int'。)

祝你好运!

编辑: 正如下面提到的,这仅适用于编译时。试图弄清指针为什么不工作时非常有帮助,但在运行时需要时不是很有用。


是的,但这在C语言中不可检查,仅在编译时有效,而在运行时无效。
con-f-use

真正。我遇到了这个问题,试图调试一些失控的指针数学,因此在编译时识别问题解决了我的问题。
Daniel Peirano

1

提到的另一个答案是,您现在可以在C11中使用 _Generic

例如,这是一个宏,它将检查某些输入是否与另一种类型兼容:

您可以像这样使用宏:

这也可以用于其他类型,包括结构。例如

并在typedef上。

但是,它并不总是能给您您所期望的答案。例如,它无法区分数组和指针。

从这里借来的答案:http : //www.robertgamble.net/2012/01/c11-generic-selections.html


0

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

当您想知道void *是否指向float或integer的内存表示形式时-您必须将此信息存储在其他位置。该语言经过专门设计,不关心char *是否指向存储为intchar的对象


0

为此,我为此编写了一个简单的C程序。它位于github中。GitHub Link

这里是如何工作的...首先将您的double转换为名为s的字符字符串。

然后使用我的dtype函数确定类型...我的函数将返回一个字符...您可以像这样使用它...

然后您可以使用比较进行检查...就是这样...

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.