簡體   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