简体   繁体   English

如果不包含头文件,如何使用来自另一个头文件的#define?

[英]How can a #define from another headder file be used if the headderfile is not included?

I'm currently working with FreeRTOS, and have noticed something, which i have not encountered before.我目前正在使用 FreeRTOS,并注意到一些我以前从未遇到过的事情。

The file "projdefs.h" uses a define from the file "FreeRTOSConfig.h" without including "FreeRTOSConfig.h" without including it.文件“projdefs.h”使用文件“FreeRTOSConfig.h”中的定义,但不包含“FreeRTOSConfig.h”而不包含它。 "projdefs.h" does not include any other files for that matter. “projdefs.h”不包含与此相关的任何其他文件。

How is this possible?这怎么可能?

The case is shown below:案例如下图:

//projdefs.h

#ifndef pdMS_TO_TICKS
    #define pdMS_TO_TICKS( xTimeInMs )    ( ( TickType_t ) ( ( ( TickType_t ) ( xTimeInMs ) * ( TickType_t ) configTICK_RATE_HZ ) / ( TickType_t ) 1000U ) )
#endif

//FreeRTOSConfig.h
#ifndef configTICK_RATE_HZ
#define configTICK_RATE_HZ (1000)
#endif

I've tried to google my way to the answer but nothing has been forthcoming.我试图用谷歌搜索我的答案,但没有任何结果。

How can a #define from another header file be used if the header file is not included?如果不包含头文件,如何使用来自另一个头文件的#define

Candidate answers.候选人的答案。

  1. Even though projdefs.h did not direclty include FreeRTOSConfig.h , projdefs.h did include some.h file that included FreeRTOSConfig.h .尽管projdefs.h没有直接包含FreeRTOSConfig.hprojdefs.h确实包含了包含FreeRTOSConfig.h的 some.h 文件。 Or maybe projdefs.h did include some.h file that included some.h file that include FreeRTOSConfig.h , etc. (OP did assert: "projdefs.h" does not include any other files for that matter.")或者可能projdefs.h确实包含 some.h 文件,其中包含 some.h 文件,其中包含FreeRTOSConfig.h等(OP 断言:“projdefs.h”不包含与此相关的任何其他文件。)

  2. projdefs.h itself or included directly (or indirectly) something that defined configTICK_RATE_HZ and the assertion that FreeRTOSConfig.h was included is incorrect. projdefs.h本身或直接(或间接)包含定义configTICK_RATE_HZ的内容,并且包含FreeRTOSConfig.h的断言是不正确的。

  3. configTICK_RATE_HZ was defined by the compiler. configTICK_RATE_HZ由编译器定义。


Design tip:设计提示:

It is often a chore to find where a define , object, function or constant was declared/defined.查找define 、对象、函数或常量的声明/定义位置通常很麻烦。

I have found using a common prefix_ for them all inside "same_prefix.h" to ease this issue.我发现在"same_prefix.h"中为它们使用一个共同的prefix_来缓解这个问题。

How can a #define from another headder file be used if the headderfile is not included?如果不包含头文件,如何使用来自另一个头文件的#define?

Macro definitions come from one of these sources:宏定义来自以下来源之一:

  • source files, including headers, read by the compiler编译器读取的源文件,包括头文件
  • compiler / standard library built-ins内置编译器/标准库
  • compiler command-line arguments编译器命令行参数

C compilers do not process source files unasked, so a macro definition will be processed from header.h only if the compiler has a reason to read header.h . C 编译器不会在未经请求的情况下处理源文件,因此仅当编译器有理由读取header.h时,才会header.h处理宏定义。 Usually, that reason is that the compiler processes an #include directive that directs it to the header.通常,这个原因是编译器处理了一个#include指令,该指令将它定向到标头。 A header can also be named directly as a file to compile, but this will put its contents into their own translation unit, so it's probably not what you're observing.标头也可以直接命名为要编译的文件,但这会将其内容放入自己的翻译单元中,因此它可能不是您所观察到的。 Some compilers also provide a means to specify headers via the command line, such as GCC's -include option , which perhaps fits your definition of "not included".一些编译器还提供了一种通过命令行指定标头的方法,例如GCC 的-include option ,这可能符合您对“不包含”的定义。 Or not.或不。

It can be the case that you get inclusion of the header in question via an obscure route, such as behind multiple levels of #include directives, or a reliance on prior #include directives to have been processed, or from an #include with a macro-generated header name, or via a symbolic-link-supported different name.可能是您通过模糊的路径包含了有问题的标头,例如在多层#include指令之后,或者依赖于先前已经处理过的#include指令,或者来自带有宏的#include -生成的标题名称,或通过符号链接支持的不同名称。

It's also possible to see a macro with the same name and replacement text that would be provided by inclusion of one header resulting from any of还可以看到具有相同名称和替换文本的宏,该宏将通过包含由任何一个产生的一个标头来提供

  • inclusion of a different header;包含不同的标题;
  • direct definition via command-line argument;通过命令行参数直接定义; or要么
  • as a compiler built-in,作为内置编译器,

and none of those are well characterized as being from a header that is not included, but they might give that impression.并且这些都没有被很好地描述为来自未包含的标头,但它们可能会给人这样的印象。


As for...至于...

The file "projdefs.h" uses a define from the file "FreeRTOSConfig.h" without including "FreeRTOSConfig.h" without including it.文件“projdefs.h”使用文件“FreeRTOSConfig.h”中的定义,但不包含“FreeRTOSConfig.h”而不包含它。 "projdefs.h" does not include any other files for that matter. “projdefs.h”不包含与此相关的任何其他文件。

... the fact that projdefs.h uses symbols that it does not define, neither directrly nor via including any other files, leads me to suppose that it simply is not a standalone header. ... projdefs.h使用它未定义的符号这一事实,既不直接也不通过包含任何其他文件,使我假设它根本不是一个独立的标头。 It depends on being #include d only at a point where either这取决于仅在任何一个点上被#include d

  • the macro pdMS_TO_TICKS is already defined, orpdMS_TO_TICKS已经定义,或者
  • the macro configTICK_RATE_HZ is already defined, and the symbol TickType_t is defined either as a type designator or as a macro expanding to a type designatorconfigTICK_RATE_HZ已经定义,符号TickType_t被定义为类型指示符或扩展为类型指示符的宏

In the beginning of FreeRTOS.h , you will notice:FreeRTOS.h的开头,您会注意到:

/* Application specific configuration options. */
#include "FreeRTOSConfig.h"

/* Basic FreeRTOS definitions. */
#include "projdefs.h"

Also, pdMS_TO_TICKS() macro is not used by the kernel itself.此外,内核本身不使用pdMS_TO_TICKS()宏。 FreeRTOS kernel always uses ticks. FreeRTOS 内核始终使用节拍。 The macro is provided for users (we, application developers) only.该宏仅供用户(我们,应用程序开发人员)使用。

There are some good answers already posted, but just to add some details about the pre-processor and header files:已经发布了一些很好的答案,但只是添加有关预处理器和头文件的一些详细信息:

Everything in a header file gets expanded into each.c file that includes it.头文件中的所有内容都会扩展到包含它的 each.c 文件中。 Formally ac file and all.h files it includes form a translation unit .正式的 ac 文件和它包含的 all.h 文件构成了一个翻译单元 So.h files don't really have a life of their own, their contents are always "glued" into the.c file by the pre-processor. So.h 文件实际上并没有自己的生命,它们的内容总是被预处理器“粘”到 .c 文件中。

This can lead to various strange or unintended side effects.这可能会导致各种奇怪或意外的副作用。 For example your FreeRTOSConfig.h will be able to access everything from projdefs.h if both were included from the same.c file and FreeRTOSConfig.h was included first.例如,您的FreeRTOSConfig.h将能够访问projdefs.h中的所有内容,前提是两者都包含在同一个.c 文件中并且首先包含FreeRTOSConfig.h Relying on this is very bad practice though, since it forces the user of the header files to include them in a certain order.但是,依赖于此是非常糟糕的做法,因为它会强制头文件的用户以特定顺序包含它们。 Instead each.h file should include every other.h file that it needs.相反,每个 .h 文件应该包含它需要的每个 other.h 文件。

And that's where the so-called "header guards" #ifndef MYHEADER_H #define MYHEADER_H ... #endif come in. Because if you don't have these in every.h file, your.c file may end up with multiple declarations/definitions of the same thing after expanding the headers.这就是所谓的“header guards” #ifndef MYHEADER_H #define MYHEADER_H ... #endif进来的地方。因为如果你没有在每个 .h 文件中都有这些,你的 .c 文件可能会以多个声明 /扩展标题后对同一事物的定义。 This is also why it is problematic to define variables or functions inside a header file - the user may end up with multiple definitions.这也是为什么在头文件中定义变量或函数是有问题的——用户最终可能会得到多个定义。

A little list of some good/idiomatic practices:一些好的/惯用做法的小清单:

  • Never force the caller to include header files in a certain order.永远不要强迫调用者以特定顺序包含头文件。
  • A header file should include all other header files it uses.头文件应该包括它使用的所有其他头文件。
  • A header file should always contain header guards.头文件应始终包含头文件保护。
  • Never declare variables in header files.切勿在头文件中声明变量。 The last resort is to declare them as extern but global variables are also bad practice.最后的办法是将它们声明为extern但全局变量也是不好的做法。
  • Avoid defining functions in header files.避免在头文件中定义函数。 Some special cases like manual optimizations with static inline may be acceptable, but also as a last resort.一些特殊情况,如使用static inline的手动优化可能是可以接受的,但也是最后的手段。

The file "projdefs.h" uses a define from the file "FreeRTOSConfig.h" without including "FreeRTOSConfig.h" without including it.文件“projdefs.h”使用文件“FreeRTOSConfig.h”中的定义,但不包含“FreeRTOSConfig.h”而不包含它。 "projdefs.h" does not include any other files for that matter. “projdefs.h”不包含与此相关的任何其他文件。

This is possible as well as you finally end in a compilation unit including both files.这是可能的,因为您最终以包含这两个文件的编译单元结束。 If you don't include one of them, the undefined macros will expand as themselves.如果您不包含其中之一,未定义的宏将自行展开。

This was historically used in the file <stdio.h> for some functions that were redefined as macros, to avoid a call to a function.这在历史上曾在文件<stdio.h>中用于某些被重新定义为宏的函数,以避免调用函数。 For example, if you do #include <stdio.h> the macro putchar() was defined as:例如,如果您执行#include <stdio.h>putchar()被定义为:

#define putchar(c) fputc(c, stdout)

so in case you include the header, the call to putchar() is translated directly into a call to fputc() while if you didn't include it, a function that did the mapping was linked into the executable.因此,如果您包含标头,对putchar()的调用将直接转换为对fputc()的调用,而如果您不包含它,则执行映射的函数将链接到可执行文件中。

#include <stdio.h>
int putchar(int c)
{
    return fputc(c, stdout);
}

and you didn't note the difference.而你没有注意到其中的区别。

This is still used in several ncurses library functions that use default screens in case you use the abbreviated form.这仍然用于几个使用默认屏幕的 ncurses 库函数,以防您使用缩写形式。 This results in a less overhead of function calls.这会减少函数调用的开销。

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

相关问题 在 C 或 C++ 中,如何防止 header 文件中先前的#define 影响另一个 Z099FB9953406FC 文件包含的 EEFC 文件? - in C or C++, how can I prevent previous #define in a header file from affecting another header file later included? 如何从另一个文件更改#define 值 - How to change #define value from another file 如何检查另一个文件中是否包含二进制文件? - How can I check if a binary file is included in another one? 如何打印C中另一个文件包含的int常量 - How to print int constant included from another file in c 如何从C代码文件创建头文件,以便可以在其他程序中使用它? - How to create a header file from a C code file so that it can be used in another program? 从另一个文件调用#define - Calling #define from another file 包含文件中的#endif可用于关闭包含文件中的#if吗? - Can #endif in an included file be used to close a #if in the including file? 来自另一个文件中的库的Vim自动补全 - Vim autocompletion from library included in another file 设置/了解如何在 header 文件中使用#define(从 cmakelist 设置) - Setting/understanding how #define is used in a header file (setting from cmakelist) 如何在一个文件中定义一个 C 函数,然后从另一个文件中调用它? - How can I define a C function in one file, then call it from another?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM