2012-09-24 45 views
8

如果编译器具有某种类型(例如ptrdiff_t)作为嵌入式类型,我不想再次键入它。我知道下面的代码不能正常工作,我预期。如何检查某个类型是否已在C编译器中定义?

#ifndef ptrdiff_t 
    typedef long int ptrdiff_t; 
#endif 

如何检查某种类型在Ç编译器已经定义?

+1

在你的具体情况。如果包含stddef.h,则应始终定义ptrdiff_t –

+2

能够在代码中测试特定定义的存在和属性称为“反射”。脚本语言倾向于支持全面反思,部分原因是脚本语言相对容易。 .NET和JVM支持反射。但对于本地语言,支持运行时反射会需要大量额外的可执行代码。一些编译时反射可以在没有这种开销的情况下得到支持,但即使在编译时C也几乎没有反射支持。 – Steve314

+0

使用像cmake或autotools这样的工具 – szx

回答

1

在你的问题你是一个有点混乱2个不同的东西:

内置的类型,如intfloat,等等,这些都是STND类型和他们的定义是所有的编译器。像__int64这样的类型不是标准的,但是它们是在一些编译器中定义的。你不需要做任何事情来使用它们。同时,如果你的代码被定义或者没有定义,你就无法弄清楚。这只能从编译器的文档中找出来。你可以写:

#ifdef MSVC 
     .... Microsoft specific code 
#else 
     .... Code for other compiler. 
#endif 

这种方法允许你创建类的compiler independent environment

除了内置的类型,还有类型来自标题。某些标题具有如下结构:

#ifndef ptrdiff_t_DEFINED 
    #define ptrdiff_t_DEFINED 
    typedef long int ptrdiff_t; 
#endif 

请注意,宏处理器defn与类型defn保持分开。您无法检查类型是否已定义,但可以轻松检查定义是否已定义。

代码中包含了哪些标题,您可以自己选择。这意味着这些定义不是in the compiler itself。它们在当前翻译单元的定义集合中。对于编译器来说,它们与您在自己的代码中编写的其他类型定义没有多大区别。

一些编译器或系统头文件没有像上面例子那样的“守护defns”。在这种情况下,你唯一能做的就是跟踪来自哪些标题,并且包括/不包括这些标题,maby使用你自己的#ifdef警卫围绕着#include声明。

5

没有办法做到这一点。在某些情况下,可能会有一个与您可以使用的类型同时定义的宏。

在你的特殊例子中,你可以使用#include <stddef.h>,它应该总是定义ptrdiff_t。

0

由于重新定义C语言保留构造通常会导致编译时错误,因此无法对其进行一般检查。 如果您对(学术/学习过程)感兴趣,您可以编写基本的编译器通行证来检查C程序中的异常/错误,以检测是否保留类型。

4

正如其他人所说,没有一个好的通用解决方案。类型名称对预处理器不可见,所以您不能使用#ifdef来测试它们的存在。

虽然有一些部分解决方案,并且它们根据给定类型的需求来自何处而有所不同。

ISO C标准有几种版本,分别在1990,1999和2011年发布。每个新标准(理论上)取代并取代前一个标准,每个标准定义一些新的类型。例如,1999 C标准添加了标头<stdbool.h><stdint.h>,以及类型bool,int32_t等。如果要使用bool类型,但仍希望代码可移植到不支持C99的实现,则可以执行一些操作像:

#if defined(__STDC__) && __STDC_VERSION__ >= 199901L 
#include <stdbool.h> 
#else 
typedef enum { false, true } bool; 
#endif 

enum类型的行为不完全相同像C99内置的bool类型,所以你需要在你如何使用它小心一点。

<stdint.h>中定义的uintptr_t类型是可选的。这是一种无符号类型,可以保存已转换的指针值而不会丢失信息;没有这种无符号类型的实现(比如,因为指针大于任何整数类型)将不会提供它。你不能直接测试类型本身,但你可以测试,给其边界的宏:

#include <stdint.h> 

#ifdef UINTMAX_MAX 
/* uintmax_t exists */ 
#else 
/* uintmax_t doesn't exist */ 
#endif 

您可能需要一个测试,包装这为__STDC____STDC_VERSION__如果您不能承担C99或更好。

long long是一种预定义类型(不是库的一部分),添加到C99中。同样,你不能测试它直接,但你可以测试定义其边界的宏:

#include <limits.h> 

#ifdef LLONG_MAX 
/* long long exists */ 
#else 
/* long long *probably* doesn't exist */ 
#endif 

最后,有一些事情你不能用C直接做的,但你可以做你程序的构建过程的一部分。例如,POSIX在POSIX专用标头<unistd.h>(它是getpid()函数返回的进程标识符的类型)中定义了pid_t类型。无法有条件包括头 - 但你可以写一个小程序,它会失败,如果标头不存在编译:

#include <unistd.h> 
pid_t dummy; 

作为构建过程的一部分,尝试编译此文件。如果成功,则向

#define HAVE_PID_T 

添加一行到配置头;如果失败,追加像

#undef HAVE_PID_T 

在你的源代码行,那么你可以写类似:

#include "config.h" 
#ifdef HAVE_PID_T 
#include <unistd.h> 
/* pid_t exists */ 
#else 
/* pid_t doesn't exist */ 
#endif 

GNU Autoconf提供了一种自动执行此类型的测试,但它被批评为过于复杂和笨拙。

所有这一切都假定,一旦您确定某个类型是否存在,您可以对该信息做一些有用的事情。对于某些类型,如bool,可以实现几乎相同的替代方法。另一方面,对于pid_t,可能不会有很好的回退,除非您仅处理所有处理进程的代码。如果你的程序不能在没有pid_tgetpid()的系统上工作,最好只编写假定它们存在的代码。如果你尝试在没有提供它们的系统上编译你的代码,它将立即无法编译,这可能是你能做的最好的事情。

相关问题