简体   繁体   English

在 C/C++ 中,是否有类似于 #ifndef 的指令用于 typedef?

[英]In C/C++, is there a directive similar to #ifndef for typedefs?

If I want to define a value only if it is not defined, I do something like this:如果我只想在未定义的情况下定义一个值,我会这样做:

#ifndef THING
#define THING OTHER_THING
#endif

What if THING is a typedef 'd identifier, and not defined?如果THINGtypedef的标识符,但未定义怎么办? I would like to do something like this:我想做这样的事情:

#ifntypedef thing_type
typedef uint32_t thing_type
#endif

The issue arose because I wanted to check to see if an external library has already defined the boolean type, but I'd be open to hearing a more general solution.出现这个问题是因为我想检查外部库是否已经定义了boolean类型,但我愿意听取更通用的解决方案。

There is no such thing in the language, nor is it needed.语言中没有这样的东西,也不需要。 Within a single project you should not have the same typedef alias referring to different types ever, as that is a violation of the ODR, and if you are going to create the same alias for the same type then just do it.在单个项目中,您不应该有相同的 typedef 别名来引用不同的类型,因为这违反了 ODR,如果您要为相同的类型创建相同的别名,那么就这样做。 The language allows you to perform the same typedef as many times as you wish and will usually catch that particular ODR (within the same translation unit):该语言允许您根据需要多次执行相同的 typedef,并且通常会捕获特定的 ODR(在同一翻译单元内):

typedef int myint;
typedef int myint;       // OK: myint is still an alias to int
//typedef double myint;  // Error: myint already defined as alias to int

If what you are intending to do is implementing a piece of functionality for different types by using a typedef to determine which to use, then you should be looking at templates rather than typedefs.如果您打算通过使用 typedef 来确定要使用哪个类型来实现不同类型的功能,那么您应该查看模板而不是 typedef。

C++ does not provide any mechanism for code to test presence of typedef , the best you can have is something like this: C++ 没有提供任何代码来测试typedef存在的机制,你可以拥有的最好的东西是这样的:

#ifndef THING_TYPE_DEFINED
#define THING_TYPE_DEFINED
typedef uint32_t thing_type 
#endif

EDIT:编辑:
As @David, is correct in his comment, this answers the how?正如@David,他的评论是正确的,这回答了如何? part but importantly misses the why?部分但重要的是错过了为什么? It can be done in the way above, If you want to do it et all, but important it you probably don't need to do it anyways, @David's answer & comment explains the details, and I think that answers the question correctly.可以按上述方式完成,如果您想全部完成,但重要的是您可能无论如何都不需要这样做,@David 的回答和评论解释了细节,我认为正确回答了这个问题。

No there is no such facility in C++ at preprocessing stage.不,C++ 在预处理阶段没有这样的设施。 At the max can do is在最大可以做的是

#ifndef thing_type
#define thing_type uint32_t 
#endif

Though this is not a good coding practice and I don't suggest it.虽然这不是一个好的编码实践,但我不建议这样做。

Preprocessor directives (like #define ) are crude text replacement tools, which know nothing about the programming language, so they can't act on any language-level definitions.预处理器指令(如#define )是粗略的文本替换工具,它对编程语言一无所知,因此它们不能作用于任何语言级别的定义。

There are two approaches to making sure a type is only defined once:有两种方法可以确保类型只定义一次:

  • Structure the code so that each definition has its place, and there's no need for multiple definitions构造代码,以便每个定义都有其位置,并且不需要多个定义
  • #define a preprocessor macro alongside the type, and use #ifndef to check for the macro definition before defining the type.在类型旁边#define一个预处理器宏,并在定义类型之前使用#ifndef检查宏定义。

The first option will generally lead to more maintainable code.第一个选项通常会导致更可维护的代码。 The second could cause subtle bugs, if you accidentally end up with different definitions of the type within one program.如果您不小心在一个程序中对类型进行了不同的定义,则第二种可能会导致细微的错误。

This might not directly answer the question, but serve as a possible solution to your problem.这可能不会直接回答问题,但可以作为您问题的可能解决方案。

Why not try something like this?为什么不尝试这样的事情呢?

#define DEFAULT_TYPE int // just for argument's sake
#ifndef MY_COOL_TYPE
     #define MY_COOL_TYPE DEFAULT_TYPE
#endif
typedef MY_COOL_TYPE My_Cool_Datatype_t;

Then if you want to customize the type, you can either define MY_COOL_TYPE somewhere above this (like in a "configure" header that is included at the top of this header) or pass it as a command line argument when compiling (as far as I know you can do this with GCC and LLVM, maybe others, too).然后,如果你想自定义类型,你可以在上面的某个地方定义 MY_COOL_TYPE(比如在这个标题顶部包含的“配置”header 中)或者在编译时将它作为命令行参数传递(据我所知知道你可以用 GCC 和 LLVM 来做到这一点,也许还有其他的)。

The problem is actually real PITA, because some APIs or SDKs redefine commonly used things.问题实际上是真正的 PITA,因为一些 API 或 SDK 重新定义了常用的东西。 I had issue that header files for a map processing software (GIS) were redefining TRUE and FALSE (generally used by windows SDK)keywords to integer literals instead of true and false keywords ( obviously, that can break SOMETHING). I had issue that header files for a map processing software (GIS) were redefining TRUE and FALSE (generally used by windows SDK)keywords to integer literals instead of true and false keywords ( obviously, that can break SOMETHING). And yes, famous joke "#define true false" is relevant.是的,著名的笑话“#define true false”是相关的。

define would never feel a typedef or constant declared in C\C++ code because preprocessor doesn't analyze code, it only scans for # statements. define 永远不会感觉到在 C\C++ 代码中声明的 typedef 或常量,因为预处理器不分析代码,它只扫描 # 语句。 And it modifies code prior to giving it to syntax analyzer.它会在将代码提供给语法分析器之前对其进行修改。 SO, in general, it's not possible.所以,一般来说,这是不可能的。

https://msdn.microsoft.com/en-us/library/5xkf423c.aspx?f=255&MSPPError=-2147217396 That one isn't portable so far, though there were known request to implement it in GCC. https://msdn.microsoft.com/en-us/library/5xkf423c.aspx?f=255&MSPPError=-2147217396到目前为止,它还不能移植,尽管已知在 Z32D8B233E3C58A262A0B7587222 中实现它的请求。 I think, it also counts as "extension" in MSVC.我认为,它也算作 MSVC 中的“扩展”。 It's a compiler statement, not a preprocessor statement, so it will not "feel" defined macros, it would detect only typedefs outside of function body.这是一个编译器语句,而不是预处理器语句,因此它不会“感觉”定义的宏,它只会检测 function 主体之外的 typedef。 "full type" there means that it will react on full definition, ignoring statements like "class SomeClass;".那里的“完整类型”意味着它将对完整定义做出反应,而忽略诸如“class SomeClass;”之类的语句。 Use it at own risk.使用它需要自担风险。

Edit: apparently it also supported on MacOS now and by Intel comiler with -fms-dialect flag (AIX\Linux?)编辑:显然它现在也支持 MacOS 和带有 -fms-dialect 标志的英特尔编译器(AIX\Linux?)

As other have already said, there are no such thing, but if you try to create an alias to different type, you'll get a compilation error:正如其他人已经说过的那样,没有这样的事情,但是如果您尝试为不同类型创建别名,则会出现编译错误:

typedef int myInt;
typedef int myInt;    // ok, same alias
typedef float myInt;  // error

However, there is a thing called ctag for finding where a typedef is defined.但是,有一个叫做ctag的东西用于查找 typedef 的定义位置。

No there is nothing like what you wanted.不,没有什么像你想要的那样。 I have had your same problem with libraries that include their own typedefs for things like bool .对于包含自己的typedefs的库,我遇到了同样的问题,例如bool It gets to be a problem when they just don't care about what you use for bool or if any other libs might be doing the same thing!!当他们只是不关心您用于bool的内容或者是否有任何其他库可能正在做同样的事情时,这将成为一个问题!

So here's what I do.所以这就是我要做的。 I edit the header file for the libs that do such things and find the typedef bool and add some code like this:我为执行此类操作的库编辑 header 文件并找到typedef bool并添加一些如下代码:

#ifdef USE_LIBNAME_BOOL
typedef unsigned char bool; // This is the lib's bool implementation
#else
#include <stdbool.h>
#endif

Notice that I included if I didn't want to use the libs' own bool typdef .请注意,如果我不想使用库自己的bool typdef ,则包括在内。 This means that you need C99 support or later.这意味着您需要 C99 或更高版本的支持。

As mentioned before this is not included in the C++ standard, but you might be able to use autotools to get the same functionality.如前所述,这不包含在 C++ 标准中,但您可以使用自动工具来获得相同的功能。

You could use the ac_cxx_bool macro to make sure bool is defined (or different routines for different datatypes).您可以使用ac_cxx_bool宏来确保定义 bool (或不同数据类型的不同例程)。

This is a good question.这是一个很好的问题。 C and Unix have a history together, and there are a lot of Unix C typedefs not available on a non-POSIX platform such as Windows (shhh Cygwin people). C 和 Unix 一起有历史,并且有很多 Unix C 类型定义在非 POSIX 平台上不可用,例如 Windows(嘘 Cygwin 人)。 You'll need to decide how to answer this question whenever you're trying to write C that's portable between these systems (shhhhh Cygwin people).每当您尝试编写可在这些系统之间移植的 C 时,您都需要决定如何回答这个问题(嘘 Cygwin 人)。

If cross-platform portability is what you need this for, then knowing the platform-specific preprocessor macro for the compilation target is sometimes helpful.如果跨平台可移植性是您所需要的,那么了解编译目标的特定于平台的预处理器宏有时会有所帮助。 Eg windows has the _WIN32 preprocessor macro defined - it's 1 whenever the compilation target is 32-bit ARM, 64-bit ARM, x86, or x64.例如 windows 定义了_WIN32预处理器宏——只要编译目标是 32 位 ARM、64 位 ARM、x86 或 x64,它就是 1。 But it's presence also informs us that we're on a Windows machine.但它的存在也告诉我们我们在一台 Windows 机器上。 This means that eg ssize_t won't be available (ssize_t, not size_t).这意味着,例如ssize_t将不可用(ssize_t,而不是 size_t)。 So you might want to do something like:所以你可能想做这样的事情:

#ifdef _WIN32
typedef long ssize_t;
#endif

By the way, people in this thread have commented about a similar pattern that is formally called a guard .顺便说一下,这个线程中的人评论了一个类似的模式,正式名称是guard You see it in header files (ie interfaces or ".h" files) a lot to prevent multiple inclusion .您在 header 文件(即接口或“.h”文件)中看到它很多,以防止多重包含 You'll hear about header guards .你会听到header 守卫

/// @file poop.h

#ifndef POOP_H
#define POOP_H

void* poop(Poop* arg);

#endif

Now I can include the header file in the implementation file poop.c and some other file like main.c , and I know they will always compile successfully and without multiple inclusion, whether they are compiled together or individually, thanks to the header guards.现在我可以将 header 文件包含在实现文件poop.c其他一些文件(如main.c )中,而且我知道它们将始终编译成功并且没有多重包含,无论它们是一起编译还是单独编译,感谢 header 守卫。

Salty seadogs write their header guards programmatically or with C++11 function-like macros. Salty seadogs 以编程方式或使用 C++11 类函数宏编写其 header 守卫。 If you like books I recommend Jens Gustedt's "Modern C".如果您喜欢书籍,我推荐 Jens Gustedt 的“Modern C”。

The solution I ended up using was including stdbool.h.我最终使用的解决方案包括 stdbool.h。 I know this doesn't solve the question of how to check if a typedef is already defined, but it does let me ensure that the boolean type is defined.我知道这并不能解决如何检查 typedef 是否已定义的问题,但它确实让我确保定义了 boolean 类型。

There is not such things.没有这样的事情。 It is possible to desactivate this duplicate_typedef compilator error.可以停用此 duplicate_typedef 编译器错误。 "typedef name has already been declared (with same type)" “typedef 名称已被声明(具有相同的类型)”

On a another hand, for some standardized typedef definition there is often a preprocessor macro defined like __bool_true_false_are_defined for bool that can be used.另一方面,对于一些标准化的 typedef 定义,通常有一个预处理器宏定义为可以使用的 bool 的 __bool_true_false_are_defined。

It is not transparent but you can try to compile it one time without typedef (just using the alias), and see if it compiles or not.它不是透明的,但您可以尝试在没有 typedef 的情况下编译一次(仅使用别名),然后查看它是否编译。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM