程式碼文件化

本章涵蓋兩個主題

  1. 如何在程式碼中加入註解,以便 Doxygen 將其納入它所產生的文件中。詳細資訊請見下一節
  2. 如何組織註解區塊的內容,使輸出看起來良好,如註解區塊的剖析章節所述。

特殊註解區塊

特殊註解區塊是 C 或 C++ 樣式的註解區塊,帶有一些額外的標記,因此 Doxygen 知道它是需要放在產生文件中的結構化文字。 下一節介紹 Doxygen 支援的各種樣式。

對於 Python、VHDL 和 Fortran 程式碼,有不同的註解慣例,可以在Python 中的註解區塊VHDL 中的註解區塊Fortran 中的註解區塊章節中找到。

C 類語言(C/C++/C#/Objective-C/PHP/Java)的註解區塊

對於程式碼中的每個實體,都有兩種(或在某些情況下是三種)描述,它們共同構成了該實體的文件;簡要描述和詳細描述,兩者都是可選的。對於方法和函數,還有第三種描述,即所謂的內文描述,它由方法或函數主體內找到的所有註解區塊的串聯組成。

允許有多個簡要或詳細描述(但不建議,因為描述出現的順序未指定)。

顧名思義,簡要描述是一個簡短的一行文字,而詳細描述則提供更長、更詳細的文件。"內文"描述也可以充當詳細描述,或描述一系列實作細節。對於 HTML 輸出,簡要描述也用於在參考項目的地方提供工具提示。

有多種方法可以將註解區塊標記為詳細描述

  1. 您可以使用 Javadoc 樣式,它由以兩個 * 開頭的 C 樣式註解區塊組成,如下所示

    /**
     * ... text ...
     */
    

  2. 或者您可以使用 Qt 樣式,並在 C 樣式註解區塊的開頭添加驚嘆號 (!),如此範例所示

    /*!
     * ... text ...
     */
    

    在這兩種情況下,中間的 * 都是可選的,因此

    /*!
     ... text ...
    */
    

    也是有效的。

  3. 第三種選擇是使用至少兩行 C++ 註解行,其中每行都以額外的斜線或驚嘆號開頭。 以下是這兩種情況的範例

    ///
    /// ... text ...
    ///
    

    //!
    //!... text ...
    //!
    

    請注意,在這種情況下,空行會結束文件區塊。

  4. 有些人喜歡讓他們的註解區塊在文件中更顯眼。為此,您可以使用以下方法

    /*******************************************//**
     *  ... text
     ***********************************************/
    

    注意:2 個斜線結束正常的註解區塊並開始特殊的註解區塊。

    注意:使用像 clang-format 這樣的重格式化程式時要小心,因為它可能會將此類註解視為 2 個單獨的註解,並在它們之間引入間距。

    /////////////////////////////////////////////////
    /// ... text ...
    /////////////////////////////////////////////////
    

    /***********************************************
     *  ... text
     ***********************************************/
    

    只要將JAVADOC_BANNER設定為YES即可。

    /**
    * JavaDoc 樣式(C 樣式)註解的簡史。
    *
    * 這是典型的 JavaDoc 樣式 C 樣式註解。它以兩個
    * 星號開頭。
    *
    * @param theory 即使只有一個可能的統一理論。它也只是一
    * 組規則和方程式。
    */
    void cstyle( int theory );
    /******************************************************************************
    * JavaDoc 樣式(C 樣式)標題註解的簡史。
    *
    * 這是典型的 JavaDoc 樣式 C 樣式「標題」註解。它以
    * 正斜線開頭,後面是一些數字 n 個星號,其中 n > 2。撰寫此方式
    * 是為了讓讀取
    * 原始碼的開發人員更容易「看到」。
    *
    * 通常,開發人員不知道這不是(預設情況下)有效的 Doxygen
    * 註解區塊!
    *
    * 但是,只要將 JAVADOC_BANNER = YES 添加到 Doxyfile,它就會
    * 如預期般運作。
    *
    * 這種註解樣式可以與 clang-format 良好搭配。
    *
    * @param theory 即使只有一個可能的統一理論。它也只是一
    * 組規則和方程式。
    ******************************************************************************/
    void javadocBanner( int theory );
    /**************************************************************************//**
    * Doxygen 樣式標題註解的簡史。
    *
    * 這是 Doxygen 樣式 C 樣式「標題」註解。它以「正常」
    * 註解開頭,然後在第一行末尾附近轉換為「特殊」註解區塊。撰寫此方式
    * 是為了讓讀取原始碼的開發人員更容易「看到」。
    * 這種註解樣式與 clang-format 的搭配效果不佳。
    * 這種註解樣式與 clang-format 的搭配效果不佳。
    *
    * @param theory 即使只有一個可能的統一理論。它也只是一
    * 組規則和方程式。
    ******************************************************************************/
    void doxygenBanner( int theory );

    按一下這裡以查看 Doxygen 產生的對應 HTML 文件。

對於簡要描述,也有幾種可能性

  1. 可以使用帶有上述註解區塊之一的\brief指令。此指令在段落結尾結束,因此詳細描述會在空行之後繼續。

    這是一個範例

    /*! \brief Brief description.
     *         Brief description continued.
     *
     *  Detailed description starts here.
     */
    

  2. 如果在組態檔中將JAVADOC_AUTOBRIEF設定為YES,則使用 Javadoc 樣式註解區塊會自動開始簡要描述,該描述會在第一個句點、問號或驚嘆號之後接著一個空格或換行符號時結束。這是一個範例

    /** Brief description which ends at this dot. Details follow
     *  here.
     */
    

    此選項對於多行特殊 C++ 註解具有相同的效果

    /// Brief description which ends at this dot. Details follow
    /// here.
    

  3. 第三種選擇是使用不跨越一行以上的特殊 C++ 樣式註解。以下是兩個範例

    /// Brief description.
    /** Detailed description. */
    

    //! Brief description.
    
    //! Detailed description
    //! starts here.
    

    請注意最後一個範例中的空行,這是將簡要描述與包含詳細描述的區塊分開所必需的。對於這種情況,JAVADOC_AUTOBRIEF也應設定為NO

如您所見,Doxygen 非常靈活。如果您有多個詳細描述,例如在以下範例中

//! Brief description, which is
//! really a detailed description since it spans multiple lines.
/*! Another detailed description!
 */

它們會被合併。請注意,即使描述位於程式碼中的不同位置,也會發生這種情況!在這種情況下,順序將取決於 Doxygen 解析程式碼的順序。

與大多數其他文件系統不同,Doxygen 也允許您將成員(包括全域函式)的文件放在定義之前。這樣,文件可以放在原始檔中,而不是標頭檔中。這可以保持標頭檔精簡,並允許成員的實作者更直接地存取文件。作為折衷方案,簡要描述可以放在宣告之前,而詳細描述可以放在成員定義之前。

將文件放在成員之後

如果您想要記錄檔案、結構、聯集、類別或列舉的成員,有時會希望將文件區塊放在成員之後,而不是之前。為此,您必須在註解區塊中加入一個額外的 < 標記。請注意,這也適用於函式的參數。

以下是一些範例

int var; /*!< Detailed description after the member */

此區塊可用於在成員之後放置 Qt 樣式的詳細文件區塊。執行相同操作的其他方法是

int var; /**< Detailed description after the member */

int var; //!< Detailed description after the member
         //!<

int var; ///< Detailed description after the member
         ///<

通常,只希望在成員之後放置簡要描述。方法如下

int var; //!< Brief description after the member

int var; ///< Brief description after the member

對於函式,可以使用@param指令來記錄參數,然後使用[in][out][in,out]來記錄方向。對於內嵌文件,也可以透過以方向屬性開頭來實現,例如

void foo(int v /**< [in] docs for input parameter v. */);

請注意,這些區塊的結構和含義與前一節中的特殊註解區塊相同,只有 < 表示成員位於區塊的前面,而不是區塊的後面。

以下是使用這些註解區塊的範例

/*! 一個測試類別 */
class Afterdoc_Test
{
public:
/** 一個列舉類型。
* 文件區塊不能放在列舉之後!
*/
enum EnumType
{
int EVal1, /**< 列舉值 1 */
int EVal2 /**< 列舉值 2 */
};
void member(); //!< 成員函式。
protected:
int value; /*!< 整數值 */
};

按一下這裡以查看 Doxygen 產生的對應 HTML 文件。

警告
這些區塊只能用於記錄成員參數。它們不能用於記錄檔案、類別、聯集、結構、群組、命名空間、巨集和列舉本身。此外,下一節中提到的結構指令(如 \class)不允許在這些註解區塊內使用。
小心使用此結構作為巨集定義的一部分,因為當在應用巨集的位置將MACRO_EXPANSION設定為 YES 時,也會替換註解,並且此註解會用作最後遇到的項目的文件,而不是巨集定義本身的文件!

範例

以下是一個使用 Qt 風格的 C++ 程式碼文件範例

//! 一個測試類別。
/*!
更詳細的類別描述。
*/
class QTstyle_Test
{
public::
//! 一個列舉。
/*! 更詳細的列舉描述。 */
enum TEnum {
TVal1, /*!< 列舉值 TVal1。 */
TVal2, /*!< 列舉值 TVal2。 */
TVal3 /*!< 列舉值 TVal3。 */
}
//! 列舉指標。
/*! 詳細資訊。 */
*enumPtr,
//! 列舉變數。
/*! 詳細資訊。 */
enumVar;
//! 一個建構子。
/*!
更詳細的建構子描述。
*/
QTstyle_Test();
//! 一個解構子。
/*!
更詳細的解構子描述。
*/
~QTstyle_Test();
//! 一個帶有兩個引數並返回整數值的普通成員。
/*!
\param a 一個整數引數。
\param s 一個常數字元指標。
\return 測試結果
\sa QTstyle_Test(), ~QTstyle_Test(), testMeToo() 和 publicVar()
*/
int testMe(int a,const char *s);
//! 一個純虛擬成員。
/*!
\sa testMe()
\param c1 第一個引數。
\param c2 第二個引數。
*/
virtual void testMeToo(char c1,char c2) = 0;
//! 一個公開變數。
/*!
詳細資訊。
*/
int publicVar;
//! 一個函式變數。
/*!
詳細資訊。
*/
int (*handler)(int a,int b);
};

點擊這裡查看 Doxygen 生成的對應 HTML 文件。

簡要描述會包含在類別、命名空間或檔案的成員概述中,並使用小的斜體字體列印(此描述可以透過在設定檔中將 BRIEF_MEMBER_DESC 設定為 NO 來隱藏)。預設情況下,簡要描述會成為詳細描述的第一句話(但可以透過將 REPEAT_BRIEF 標籤設定為 NO 來變更)。對於 Qt 風格來說,簡要描述和詳細描述都是可選的。

預設情況下,Javadoc 風格的文檔區塊行為與 Qt 風格的文檔區塊相同。然而,這並不符合 Javadoc 規範,在 Javadoc 規範中,文檔區塊的第一句話會自動被視為簡要描述。要啟用此行為,您應該在設定檔中將 JAVADOC_AUTOBRIEF 設定為 YES。如果您啟用此選項,並且想要在句子中間放置一個句點而不結束句子,您應該在其後放置一個反斜線和一個空格。以下是一個範例

  /** Brief description (e.g.\ using only a few words). Details follow. */

以下是與上面相同的程式碼片段,這次使用 Javadoc 風格撰寫文檔,並且將 JAVADOC_AUTOBRIEF 設定為 YES

/**
* 一個測試類別。更詳細的類別描述。
*/
class Javadoc_Test
{
public::
/**
* 一個列舉。
* 更詳細的列舉描述。
*/
enum TEnum {
TVal1, /**< 列舉值 TVal1。 */
TVal2, /**< 列舉值 TVal2。 */
TVal3 /**< 列舉值 TVal3。 */
}
*enumPtr, /**< 列舉指標。詳細資訊。 */
enumVar; /**< 列舉變數。詳細資訊。 */
/**
* 一個建構子。
* 更詳細的建構子描述。
*/
Javadoc_Test();
/**
* 一個解構子。
* 更詳細的解構子描述。
*/
~Javadoc_Test();
/**
* 一個帶有兩個引數並返回整數值的普通成員。
* @param a 一個整數引數。
* @param s 一個常數字元指標。
* @see Javadoc_Test()
* @see ~Javadoc_Test()
* @see testMeToo()
* @see publicVar()
* @return 測試結果
*/
int testMe(int a,const char *s);
/**
* 一個純虛擬成員。
* @see testMe()
* @param c1 第一個引數。
* @param c2 第二個引數。
*/
virtual void testMeToo(char c1,char c2) = 0;
/**
* 一個公開變數。
* 詳細資訊。
*/
int publicVar;
/**
* 一個函式變數。
* 詳細資訊。
*/
int (*handler)(int a,int b);
};

點擊這裡查看 Doxygen 生成的對應 HTML 文件。

同樣地,如果想要將 Qt 風格文檔區塊的第一句話自動視為簡要描述,可以在設定檔中將 QT_AUTOBRIEF 設定為 YES。

在其他位置的文檔

在前一節的範例中,註解區塊始終位於檔案、類別或命名空間的宣告或定義之前,或位於其成員的之前之後。雖然這通常很方便,但有時可能會有一些原因需要將文檔放置在其他地方。對於編寫檔案的文檔,這是必需的,因為沒有「在檔案之前」這種東西。

Doxygen 允許您將文檔區塊放置在任何地方(例外情況是在函式主體內部或在普通的 C 風格註解區塊內部)。

如果沒有將文檔區塊直接放置在項目之前(或之後),則需要付出代價,即需要在文檔區塊內放置一個結構命令,這會導致一些資訊重複。因此,在實務中,您應該避免使用結構命令,除非其他需求迫使您這樣做。

結構命令(如所有其他命令)以反斜線(\)或 at 符號(@)(如果您偏好 Javadoc 風格)開頭,後面接著命令名稱和一個或多個參數。例如,如果您想要為上面範例中的類別 Test 編寫文檔,您也可以將以下文檔區塊放置在 Doxygen 讀取的輸入中的某個位置

/*! \class Test
    \brief A test class.

    A more detailed class description.
*/

這裡使用特殊命令 \class 來指示註解區塊包含類別 Test 的文檔。其他結構命令包括

  • \struct:用於為 C 結構編寫文檔。
  • \union:用於為聯合編寫文檔。
  • \enum:用於為列舉型別編寫文檔。
  • \fn:用於為函式編寫文檔。
  • \var:用於為變數或 typedef 或列舉值編寫文檔。
  • \def:用於為 #define 編寫文檔。
  • \typedef:用於為型別定義編寫文檔。
  • \file:用於為檔案編寫文檔。
  • \namespace:用於為命名空間編寫文檔。
  • \package:用於為 Java 套件編寫文檔。
  • \interface:用於為 IDL 介面編寫文檔。

有關這些命令和許多其他命令的詳細資訊,請參閱特殊命令一節。

要為 C++ 類別的成員編寫文檔,您還必須為類別本身編寫文檔。命名空間也適用相同的情況。要為全域 C 函式、typedef、列舉或預處理器定義編寫文檔,您必須先為包含它的檔案編寫文檔(通常這會是一個標頭檔,因為該檔案包含匯出到其他原始碼檔案的資訊)。

注意
讓我們重複一遍,因為它經常被忽略:要為全域物件(函式、typedef、列舉、巨集等)編寫文檔,您必須為定義它們的檔案編寫文檔。換句話說,此檔案中必須至少有
/*! \file */ 
/** @file */ 
行。

以下是一個名為 structcmd.h 的 C 標頭的範例,該標頭使用結構命令進行文檔編寫

/*! \file structcmd.h
\brief 一個帶有文檔的檔案。
詳細資訊。
*/
/*! \def MAX(a,b)
\brief 一個返回 \a a 和 \a b 最大值的巨集。
詳細資訊。
*/
/*! \var typedef unsigned int UINT32
\brief 一個 的型別定義。
詳細資訊。
*/
/*! \var int errno
\brief 包含最後一個錯誤碼。
\warning 不是執行緒安全的!
*/
/*! \fn int open(const char *pathname,int flags)
\brief 開啟一個檔案描述器。
\param pathname 描述器的名稱。
\param flags 開啟旗標。
*/
/*! \fn int close(int fd)
\brief 關閉檔案描述器 \a fd。
\param fd 要關閉的描述器。
*/
/*! \fn size_t write(int fd,const char *buf, size_t count)
\brief 將 \a buf 中的 \a count 位元組寫入檔案描述器 \a fd。
\param fd 要寫入的描述器。
\param buf 要寫入的資料緩衝區。
\param count 要寫入的位元組數。
*/
/*! \fn int read(int fd,char *buf,size_t count)
\brief 從檔案描述器讀取位元組。
\param fd 要讀取的描述器。
\param buf 要讀取的緩衝區。
\param count 要讀取的位元組數。
*/
#define MAX(a,b) (((a)>(b))?(a):(b))
typedef unsigned int UINT32;
int errno;
int open(const char *,int);
int close(int);
size_t write(int,const char *, size_t);
int read(int,char *,size_t);

點擊這裡查看 Doxygen 生成的對應 HTML 文件。

由於上面範例中的每個註解區塊都包含一個結構命令,因此所有註解區塊都可以移動到另一個位置或輸入檔案(例如原始碼檔案),而不會影響產生的文檔。這種方法的缺點是原型會重複,因此所有變更都必須進行兩次!因此,您應該先考慮是否真的需要這樣做,並盡可能避免使用結構命令。我經常收到在函式前面的註解區塊中包含 \fn 命令的範例。這顯然是 \fn 命令是多餘的,只會導致問題的情況。

當您在具有以下副檔名之一的檔案中放置註解區塊時:.dox.txt.doc.md.markdown,或者當副檔名透過 EXTENSION_MAPPING 對應到 md 時,Doxygen 會從檔案清單中隱藏此檔案。

如果您有一個 Doxygen 無法解析但仍想記錄的文件,您可以使用 \verbinclude 來原樣顯示它,例如:

/*! \file myscript.sh
 *  Look at this nice script:
 *  \verbinclude myscript.sh
 */

請確保該腳本已明確列在 INPUT 中,或者 FILE_PATTERNS 包含 .sh 擴展名,並且該腳本可以在通過 EXAMPLE_PATH 設定的路徑中找到。

Python 中的註解區塊

對於 Python,有一種使用所謂的文檔字串 (""") 來記錄程式碼的標準方法。這些字串儲存在 __doc__ 中,並且可以在運行時檢索。Doxygen 會提取這些註解,並假設它們必須以預先格式化的方式呈現。

"""@package docstring
這個模組的文件。
更多詳細資訊。
"""
def func()
"""一個函數的文件。
更多詳細資訊。
"""
pass
class PyClass
"""一個類別的文件。
更多詳細資訊。
"""
def __init__(self)
"""建構子。"""
self._memVar = 0;
def PyMethod(self)
"""一個方法的文件。"""
pass

點擊這裡查看由 Doxygen 產生的相應 HTML 文件。

注意
當使用 """ 時,Doxygen 的任何特殊指令都不受支援,並且文字會以逐字文字顯示,請參閱\verbatim。若要使用 Doxygen 的特殊指令並將文字作為一般文件而不是 """,請使用 """! 或在設定檔中將 PYTHON_DOCSTRING 設定為 NO
除了 """ 之外,也可以使用 '''

還有一種使用以 "##" 或 "##<" 開頭的註解來記錄 Python 程式碼的方式。這種註解區塊類型更符合 Doxygen 支援的其他語言的文件區塊工作方式,並且也允許使用特殊指令。

以下是相同的範例,但現在使用 Doxygen 樣式的註解:

## @package pyexample
# 這個模組的文件。
#
# 更多詳細資訊。
## 一個函數的文件。
#
# 更多詳細資訊。
def func()
pass
## 一個類別的文件。
#
# 更多詳細資訊。
class PyClass
## 建構子。
def __init__(self)
self._memVar = 0;
## 一個方法的文件。
# @param self 物件指標。
def PyMethod(self)
pass
## 一個類別變數。
classVar = 0;
## @var _memVar
# 一個成員變數

點擊這裡查看由 Doxygen 產生的相應 HTML 文件。

由於 Python 看起來更像 Java 而不是 C 或 C++,您應該在設定檔中將 OPTIMIZE_OUTPUT_JAVA 設定為 YES

VHDL 中的註解區塊

對於 VHDL,註解通常以 "--" 開頭。Doxygen 會提取以 "--!" 開頭的註解。VHDL 中只有兩種註解區塊類型:單行 "--!" 註解,表示簡短的描述,以及多行 "--!" 註解(其中每行重複 "--!" 前綴),表示詳細的描述。

註解始終位於被記錄的項目之前,但有一個例外:對於端口,註解也可以位於項目之後,然後被視為端口的簡短描述。

以下是一個包含 Doxygen 註解的 VHDL 檔案範例:

-------------------------------------------------------
--! @file
--! @brief 使用 with-select 的 2:1 多工器
-------------------------------------------------------
--! 使用標準函式庫
library ieee;
--! 使用邏輯元件
use ieee.std_logic_1164.all;
--! 多工器實體簡短描述
--! 這個多工器設計元素的詳細描述。
--! mux 設計元素的詳細描述。
entity mux_using_with is
port (
din_0 : in std_logic; --! 多工器第一個輸入
din_1 : in std_logic; --! 多工器第二個輸入
sel : in std_logic; --! 選擇輸入
mux_out : out std_logic --! 多工器輸出
);
end entity;
--! @brief MUX 的架構定義
--! @details 關於這個多工器元素的更多詳細資訊。
architecture behavior of mux_using_with is
begin
with (sel) select
mux_out <= din_0 when '0',
din_1 when others;
end architecture;

點擊這裡查看由 Doxygen 產生的相應 HTML 文件。

從 VHDL 2008 開始,也可以使用 /* 樣式的註解。
Doxygen 會將 /* ... */ 作為普通註解處理,並將 /*! ... */ 樣式的註解作為 Doxygen 解析的特殊註解處理。

為了獲得正確的外觀輸出,您需要在設定檔中將 OPTIMIZE_OUTPUT_VHDL 設定為 YES。這也會影響許多其他設定。如果它們沒有被正確設定,Doxygen 會產生警告,說明哪些設定被覆蓋。

Fortran 中的註解區塊

當使用 Doxygen 處理 Fortran 程式碼時,您應該將 OPTIMIZE_FOR_FORTRAN 設定為 YES

解析器會嘗試猜測原始碼是固定格式的 Fortran 還是自由格式的 Fortran 程式碼。這可能並不總是正確的。如果不是,則應使用 EXTENSION_MAPPING 來更正。通過設定 EXTENSION_MAPPING = f=FortranFixed f90=FortranFree,副檔名為 f 的檔案會被解釋為固定格式的 Fortran 程式碼,而副檔名為 f90 的檔案則被解釋為自由格式的 Fortran 程式碼。

對於 Fortran,"!>" 或 "!<" 會開始註解,而 "!!" 或 "!>" 可用於將單行註解延續為多行註解。

以下是一個帶有註解的 Fortran 子程式範例:

!> 建立聚集的限制矩陣
!! 方法。
!! @param aggr 關於聚集的資訊
!! @todo 處理特殊情況
subroutine intrestbuild(A,aggr,Restrict,A_ghost)
implicit none
Type(SpMtx), intent(in) :: A !< 我們的精細級別矩陣
Type(Aggrs), intent(in) :: aggr
Type(SpMtx), intent(out) :: Restrict !< 我們的限制矩陣
!...
end subroutine

作為替代方案,您也可以在固定格式的程式碼中使用註解:

C> 函式註解
C> 另一行註解
function a(i)
C> 輸入參數
integer i
end function A

註解區塊的剖析

前一節重點介紹如何讓 Doxygen 知道您程式碼中的註解,它解釋了簡短描述和詳細描述之間的差異,以及結構指令的使用。

在本節中,我們將探討註解區塊本身的內容。

Doxygen 支援各種格式化註解的樣式。

最簡單的形式是使用純文字。這將在輸出中原樣顯示,並且非常適合簡短的描述。

對於較長的描述,您通常會發現需要一些更結構化的內容,例如逐字文字區塊、列表或簡單表格。為此,Doxygen 支援 Markdown 語法,包括 Markdown Extra 擴展的部分內容。

Markdown 的設計目的是非常容易閱讀和寫作。其格式的靈感來自純文字郵件。Markdown 非常適合簡單、通用的格式設定,例如您專案的簡介頁面。Doxygen 也支援直接讀取 markdown 檔案。如需更多詳細資訊,請參閱 Markdown 支援 章節。

對於程式語言特定的格式設定,Doxygen 在 Markdown 格式設定之上還有兩種額外的標記形式。

  1. Javadoc 類的標記。請參閱 特殊指令,以取得 Doxygen 支援的所有指令的完整概述。
  2. C# 標準中指定的 XML 標記。請參閱 XML 指令,以取得 Doxygen 支援的 XML 指令。

如果這仍然不夠,Doxygen 也支援 子集HTML 標記語言。

前往下一節或返回索引