如何检查某个类型是否已在C编译器中定义?

时间:2021-10-19 14:54:39

If a compiler has a certain type (ex. ptrdiff_t) as an embedded type, I don't want to typedef it again. I know that below code does not work properly that I expected.

如果编译器具有某种类型(例如ptrdiff_t)作为嵌入类型,我不想再次键入它。我知道下面的代码不能正常工作。

#ifndef ptrdiff_t 
    typedef long int ptrdiff_t;
#endif

How can I check a certain type is already defined in the C compiler?

如何检查C编译器中是否已定义某种类型?

4 个解决方案

#1


1  

In your question you are a bit confusing 2 different things:

在你的问题中,你有点混淆两个不同的东西:

The built in types, like int, float, etc. These are stnd types and they are defined is all compilers. Types like __int64 are not standard, but they are defined in some of the compilers. You do not need to do anything to use them. At the same time you cannot figure out in your code if they are defined or not. This can be figured out only from the docs on the compiler. You can write:

内置类型,如int,float等。这些是stnd类型,它们被定义为所有编译器。像__int64这样的类型不是标准的,但它们在某些编译器中定义。您无需执行任何操作即可使用它们。同时,如果定义与否,您无法在代码中找出答案。这只能从编译器上的文档中找出。你可以写:

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

This approach allows you to create sort of compiler independent environment.

这种方法允许您创建一种独立于编译器的环境。

Besides the built in types, there are types that come from the headers. Some headers have constructs like:

除了内置类型,还有来自标题的类型。一些头文件的结构如下:

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

Note that the macroprocessor defn stays apart from the defn of the type. You cannot check if the type is defined or not, but you can easily check if the definition is defined.

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

What headers are included in your code you deside yourself. This means that these definitions are not in the compiler itself. They are in the set of definitions of the current translation unit. For compiler they have little difference from other type definitions that you write in your own code.

你自己想要的代码中包含哪些标题。这意味着这些定义不在编译器本身中。它们位于当前翻译单元的定义集中。对于编译器,它们与您在自己的代码中编写的其他类型定义几乎没有区别。

Some compiler or system headers for not have "guarding defns" like in the example above. In this case the only thing that you can do is to track from what headers thay are coming and include/not include these headers, maby using your own #ifdef guards around the #include statements.

某些编译器或系统头文件没有“保护定义”,如上例所示。在这种情况下,你唯一可以做的就是跟踪来自哪些标题并包含/不包含这些标题,maby使用#include语句围绕#include语句保护#ifdef。

#2


5  

There's no way to do that in general. In some cases there may be a macro that is defined at the same time as the type that you can use.

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

In your particular example, you can #include <stddef.h>, which should always define ptrdiff_t.

在您的特定示例中,您可以#include ,它应始终定义ptrdiff_t。

#3


4  

As others have said, there is no good general solution to this. Type names are not visible to the preprocessor, so you can't use #ifdef to test for their existence.

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

There are a number of partial solutions, though, and they vary depending on where the requirements for a given type came from.

但是,有许多部分解决方案,它们取决于给定类型的要求来自何处。

There are several versions of the ISO C standard, issued in 1990, 1999, and 2011. Each new standard (in theory) supersedes and replaces the previous one, and each one defines some new types. For example the 1999 C standard added headers <stdbool.h> and <stdint.h>, and types bool, int32_t, etc. If you want to use the bool type, but still want your code to be portable to implementations that don't support C99, you can do something like:

在1990年,1999年和2011年发布了ISO C标准的几个版本。每个新标准(理论上)取代并替换前一个,每个都定义了一些新类型。例如,1999 C标准添加了头文件 ,并且类型为bool,int32_t等。如果你想使用bool类型,但仍然希望你的代码可以移植到不能实现的实现t支持C99,你可以这样做:

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

The enum type doesn't behave exactly like C99's built-in bool type, so you need to be a little careful in how you use it.

枚举类型的行为与C99的内置bool类型不完全相同,因此您需要对使用它的方式稍加注意。

The type uintptr_t, defined in <stdint.h> is optional. It's an unsigned type that can hold a converted void* pointer value without loss of information; an implementation that has no such unsigned type (say, because pointers are bigger than any integer type) won't provide it. You can't directly test for the type itself, but you can test for the macros that give its bounds:

中定义的类型uintptr_t是可选的。它是一个无符号类型,可以保存转换后的void *指针值而不会丢失信息;没有这种无符号类型的实现(比方说因为指针大于任何整数类型)都不会提供它。您无法直接测试类型本身,但您可以测试提供其边界的宏:

#include <stdint.h>

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

You may need to wrap this in a test for __STDC__ and __STDC_VERSION__ if you can't assume C99 or better.

如果你不能假设C99或更好,你可能需要在__STDC__和__STDC_VERSION__的测试中包装它。

The type long long is a predefined type (not part of the library), added in C99. Again, you can't test for it directly, but you can test for the macros that define its bounds:

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

#include <limits.h>

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

Finally, there are things you can't do directly in C, but that you can do as part of your program's build process. For example, POSIX defines a type pid_t in the POSIX-specific header <unistd.h> (it's the type of a process identifier, returned by the getpid() function). You can't conditionally include a header -- but you can write a small program that will fail to compile if the header doesn't exist:

最后,有些事情你不能直接用C做,但是你可以把它作为程序构建过程的一部分。例如,POSIX在POSIX特定的头 中定义了一个类型pid_t(它是由getpid()函数返回的进程标识符的类型)。您不能有条件地包含标头 - 但是如果标头不存在,您可以编写一个无法编译的小程序:

#include <unistd.h>
pid_t dummy;

As part of your build process, try to compile this file. If it succeeds, append a line like

作为构建过程的一部分,尝试编译此文件。如果成功,请附加一行

#define HAVE_PID_T

to a configuration header; if it fails, append a line like

到配置头;如果失败,请附加一行

#undef HAVE_PID_T

In your source code, you can then write something like:

在源代码中,您可以编写如下内容:

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

GNU Autoconf provides a way to automate this kind of test, but it's been criticized for being overly complex and unwieldy.

GNU Autoconf提供了一种自动化这种测试的方法,但它因过于复杂和笨拙而受到批评。

All of this assumes that, once you've determined whether a type exists, you can do something useful with that information. For some types, like bool, you can implement a nearly equivalent alternative. For pid_t, on the other hand, there likely isn't a good fallback, unless you simply #ifdef out all the code that deals with processes. If your program just isn't going to work on a system that doesn't have pid_t and getpid(), it might be best to just write code that assumes they exist. If you try to compile your code on a system that doesn't provide them, it will immediately fail to compile, and that may be the best thing you can do.

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

#4


0  

Since redefining a C language reserved construct would generally lead to a compile time error, it is not possible to check it in general. If you are interested(for academic/learning process), you can write a basic compiler pass to check for exceptions/errors on your C program to detect if a type is reserved or not.

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

#1


1  

In your question you are a bit confusing 2 different things:

在你的问题中,你有点混淆两个不同的东西:

The built in types, like int, float, etc. These are stnd types and they are defined is all compilers. Types like __int64 are not standard, but they are defined in some of the compilers. You do not need to do anything to use them. At the same time you cannot figure out in your code if they are defined or not. This can be figured out only from the docs on the compiler. You can write:

内置类型,如int,float等。这些是stnd类型,它们被定义为所有编译器。像__int64这样的类型不是标准的,但它们在某些编译器中定义。您无需执行任何操作即可使用它们。同时,如果定义与否,您无法在代码中找出答案。这只能从编译器上的文档中找出。你可以写:

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

This approach allows you to create sort of compiler independent environment.

这种方法允许您创建一种独立于编译器的环境。

Besides the built in types, there are types that come from the headers. Some headers have constructs like:

除了内置类型,还有来自标题的类型。一些头文件的结构如下:

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

Note that the macroprocessor defn stays apart from the defn of the type. You cannot check if the type is defined or not, but you can easily check if the definition is defined.

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

What headers are included in your code you deside yourself. This means that these definitions are not in the compiler itself. They are in the set of definitions of the current translation unit. For compiler they have little difference from other type definitions that you write in your own code.

你自己想要的代码中包含哪些标题。这意味着这些定义不在编译器本身中。它们位于当前翻译单元的定义集中。对于编译器,它们与您在自己的代码中编写的其他类型定义几乎没有区别。

Some compiler or system headers for not have "guarding defns" like in the example above. In this case the only thing that you can do is to track from what headers thay are coming and include/not include these headers, maby using your own #ifdef guards around the #include statements.

某些编译器或系统头文件没有“保护定义”,如上例所示。在这种情况下,你唯一可以做的就是跟踪来自哪些标题并包含/不包含这些标题,maby使用#include语句围绕#include语句保护#ifdef。

#2


5  

There's no way to do that in general. In some cases there may be a macro that is defined at the same time as the type that you can use.

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

In your particular example, you can #include <stddef.h>, which should always define ptrdiff_t.

在您的特定示例中,您可以#include ,它应始终定义ptrdiff_t。

#3


4  

As others have said, there is no good general solution to this. Type names are not visible to the preprocessor, so you can't use #ifdef to test for their existence.

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

There are a number of partial solutions, though, and they vary depending on where the requirements for a given type came from.

但是,有许多部分解决方案,它们取决于给定类型的要求来自何处。

There are several versions of the ISO C standard, issued in 1990, 1999, and 2011. Each new standard (in theory) supersedes and replaces the previous one, and each one defines some new types. For example the 1999 C standard added headers <stdbool.h> and <stdint.h>, and types bool, int32_t, etc. If you want to use the bool type, but still want your code to be portable to implementations that don't support C99, you can do something like:

在1990年,1999年和2011年发布了ISO C标准的几个版本。每个新标准(理论上)取代并替换前一个,每个都定义了一些新类型。例如,1999 C标准添加了头文件 ,并且类型为bool,int32_t等。如果你想使用bool类型,但仍然希望你的代码可以移植到不能实现的实现t支持C99,你可以这样做:

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

The enum type doesn't behave exactly like C99's built-in bool type, so you need to be a little careful in how you use it.

枚举类型的行为与C99的内置bool类型不完全相同,因此您需要对使用它的方式稍加注意。

The type uintptr_t, defined in <stdint.h> is optional. It's an unsigned type that can hold a converted void* pointer value without loss of information; an implementation that has no such unsigned type (say, because pointers are bigger than any integer type) won't provide it. You can't directly test for the type itself, but you can test for the macros that give its bounds:

中定义的类型uintptr_t是可选的。它是一个无符号类型,可以保存转换后的void *指针值而不会丢失信息;没有这种无符号类型的实现(比方说因为指针大于任何整数类型)都不会提供它。您无法直接测试类型本身,但您可以测试提供其边界的宏:

#include <stdint.h>

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

You may need to wrap this in a test for __STDC__ and __STDC_VERSION__ if you can't assume C99 or better.

如果你不能假设C99或更好,你可能需要在__STDC__和__STDC_VERSION__的测试中包装它。

The type long long is a predefined type (not part of the library), added in C99. Again, you can't test for it directly, but you can test for the macros that define its bounds:

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

#include <limits.h>

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

Finally, there are things you can't do directly in C, but that you can do as part of your program's build process. For example, POSIX defines a type pid_t in the POSIX-specific header <unistd.h> (it's the type of a process identifier, returned by the getpid() function). You can't conditionally include a header -- but you can write a small program that will fail to compile if the header doesn't exist:

最后,有些事情你不能直接用C做,但是你可以把它作为程序构建过程的一部分。例如,POSIX在POSIX特定的头 中定义了一个类型pid_t(它是由getpid()函数返回的进程标识符的类型)。您不能有条件地包含标头 - 但是如果标头不存在,您可以编写一个无法编译的小程序:

#include <unistd.h>
pid_t dummy;

As part of your build process, try to compile this file. If it succeeds, append a line like

作为构建过程的一部分,尝试编译此文件。如果成功,请附加一行

#define HAVE_PID_T

to a configuration header; if it fails, append a line like

到配置头;如果失败,请附加一行

#undef HAVE_PID_T

In your source code, you can then write something like:

在源代码中,您可以编写如下内容:

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

GNU Autoconf provides a way to automate this kind of test, but it's been criticized for being overly complex and unwieldy.

GNU Autoconf提供了一种自动化这种测试的方法,但它因过于复杂和笨拙而受到批评。

All of this assumes that, once you've determined whether a type exists, you can do something useful with that information. For some types, like bool, you can implement a nearly equivalent alternative. For pid_t, on the other hand, there likely isn't a good fallback, unless you simply #ifdef out all the code that deals with processes. If your program just isn't going to work on a system that doesn't have pid_t and getpid(), it might be best to just write code that assumes they exist. If you try to compile your code on a system that doesn't provide them, it will immediately fail to compile, and that may be the best thing you can do.

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

#4


0  

Since redefining a C language reserved construct would generally lead to a compile time error, it is not possible to check it in general. If you are interested(for academic/learning process), you can write a basic compiler pass to check for exceptions/errors on your C program to detect if a type is reserved or not.

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