繁体   English   中英

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

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

我目前正在使用 FreeRTOS,并注意到一些我以前从未遇到过的事情。

文件“projdefs.h”使用文件“FreeRTOSConfig.h”中的定义,但不包含“FreeRTOSConfig.h”而不包含它。 “projdefs.h”不包含与此相关的任何其他文件。

这怎么可能?

案例如下图:

//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

我试图用谷歌搜索我的答案,但没有任何结果。

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

候选人的答案。

  1. 尽管projdefs.h没有直接包含FreeRTOSConfig.hprojdefs.h确实包含了包含FreeRTOSConfig.h的 some.h 文件。 或者可能projdefs.h确实包含 some.h 文件,其中包含 some.h 文件,其中包含FreeRTOSConfig.h等(OP 断言:“projdefs.h”不包含与此相关的任何其他文件。)

  2. projdefs.h本身或直接(或间接)包含定义configTICK_RATE_HZ的内容,并且包含FreeRTOSConfig.h的断言是不正确的。

  3. configTICK_RATE_HZ由编译器定义。


设计提示:

查找define 、对象、函数或常量的声明/定义位置通常很麻烦。

我发现在"same_prefix.h"中为它们使用一个共同的prefix_来缓解这个问题。

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

宏定义来自以下来源之一:

  • 编译器读取的源文件,包括头文件
  • 内置编译器/标准库
  • 编译器命令行参数

C 编译器不会在未经请求的情况下处理源文件,因此仅当编译器有理由读取header.h时,才会header.h处理宏定义。 通常,这个原因是编译器处理了一个#include指令,该指令将它定向到标头。 标头也可以直接命名为要编译的文件,但这会将其内容放入自己的翻译单元中,因此它可能不是您所观察到的。 一些编译器还提供了一种通过命令行指定标头的方法,例如GCC 的-include option ,这可能符合您对“不包含”的定义。 或不。

可能是您通过模糊的路径包含了有问题的标头,例如在多层#include指令之后,或者依赖于先前已经处理过的#include指令,或者来自带有宏的#include -生成的标题名称,或通过符号链接支持的不同名称。

还可以看到具有相同名称和替换文本的宏,该宏将通过包含由任何一个产生的一个标头来提供

  • 包含不同的标题;
  • 通过命令行参数直接定义; 要么
  • 作为内置编译器,

并且这些都没有被很好地描述为来自未包含的标头,但它们可能会给人这样的印象。


至于...

文件“projdefs.h”使用文件“FreeRTOSConfig.h”中的定义,但不包含“FreeRTOSConfig.h”而不包含它。 “projdefs.h”不包含与此相关的任何其他文件。

... projdefs.h使用它未定义的符号这一事实,既不直接也不通过包含任何其他文件,使我假设它根本不是一个独立的标头。 这取决于仅在任何一个点上被#include d

  • pdMS_TO_TICKS已经定义,或者
  • configTICK_RATE_HZ已经定义,符号TickType_t被定义为类型指示符或扩展为类型指示符的宏

FreeRTOS.h的开头,您会注意到:

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

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

此外,内核本身不使用pdMS_TO_TICKS()宏。 FreeRTOS 内核始终使用节拍。 该宏仅供用户(我们,应用程序开发人员)使用。

已经发布了一些很好的答案,但只是添加有关预处理器和头文件的一些详细信息:

头文件中的所有内容都会扩展到包含它的 each.c 文件中。 正式的 ac 文件和它包含的 all.h 文件构成了一个翻译单元 So.h 文件实际上并没有自己的生命,它们的内容总是被预处理器“粘”到 .c 文件中。

这可能会导致各种奇怪或意外的副作用。 例如,您的FreeRTOSConfig.h将能够访问projdefs.h中的所有内容,前提是两者都包含在同一个.c 文件中并且首先包含FreeRTOSConfig.h 但是,依赖于此是非常糟糕的做法,因为它会强制头文件的用户以特定顺序包含它们。 相反,每个 .h 文件应该包含它需要的每个 other.h 文件。

这就是所谓的“header guards” #ifndef MYHEADER_H #define MYHEADER_H ... #endif进来的地方。因为如果你没有在每个 .h 文件中都有这些,你的 .c 文件可能会以多个声明 /扩展标题后对同一事物的定义。 这也是为什么在头文件中定义变量或函数是有问题的——用户最终可能会得到多个定义。

一些好的/惯用做法的小清单:

  • 永远不要强迫调用者以特定顺序包含头文件。
  • 头文件应该包括它使用的所有其他头文件。
  • 头文件应始终包含头文件保护。
  • 切勿在头文件中声明变量。 最后的办法是将它们声明为extern但全局变量也是不好的做法。
  • 避免在头文件中定义函数。 一些特殊情况,如使用static inline的手动优化可能是可以接受的,但也是最后的手段。

文件“projdefs.h”使用文件“FreeRTOSConfig.h”中的定义,但不包含“FreeRTOSConfig.h”而不包含它。 “projdefs.h”不包含与此相关的任何其他文件。

这是可能的,因为您最终以包含这两个文件的编译单元结束。 如果您不包含其中之一,未定义的宏将自行展开。

这在历史上曾在文件<stdio.h>中用于某些被重新定义为宏的函数,以避免调用函数。 例如,如果您执行#include <stdio.h>putchar()被定义为:

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

因此,如果您包含标头,对putchar()的调用将直接转换为对fputc()的调用,而如果您不包含它,则执行映射的函数将链接到可执行文件中。

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

而你没有注意到其中的区别。

这仍然用于几个使用默认屏幕的 ncurses 库函数,以防您使用缩写形式。 这会减少函数调用的开销。

暂无
暂无

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

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