Files
sarasacw-omrf/assets/c-friendly-ffi-design/c-cpp-side/docstring.md
T

372 lines
10 KiB
Markdown
Raw Normal View History

2026-08-13 21:40:16 +08:00
# C/C++ Headers Docstring
This chapter describes how to write docstrings for the C/C++ header files.
## Docstring Format
We require writing docstrings in the Doxygen format for the C/C++ header files.
## Docstring Style
We require writing Doxygen docstrings in the `/** */` form instead of the `///` form, as shown below:
```c
/**
* This is our required Doxygen style.
*
* A brown fox jumps over a lazy dog.
* Another brown fox jumps over a lazy dog.
*/
```
When the whole docstring consists of only the `@brief` item and does not wrap lines, it is allowed to shrink it into a single line, for example:
```c
/** A very simple type which can be introduced within one sentence. */
using SimpleType = int;
```
In no case do we allow the trailing comment style. For example, the following is not allowed:
```c++
/** Foo bar enum class example. */
enum class FlFooBar : uint32_t {
Variant1 = 0u, /**< Foo bar variant 1. */
Variant2 = 1u /**< Foo bar variant 2. */
};
```
## Docstring Targets
We require writing docstrings for the following elements.
### Function Docstring
A docstring must be written for every function,
including functions exposed directly in namespace, and object (class or struct) functions.
The docstring must contain:
- `@brief`
The docstring must conditionally contain:
- `@param`
- Must be present when there are parameters, and must cover all parameters.
- Must use the `[in]` or `[out]` modifier to indicate the direction of parameter passing.
- `@return`
- Must be present when the return value is not `void`.
- `@throws`
- Must be present only in the C++ header files, and only when the function can throw an exception.
The docstring may optionally contain:
- `@details` (when `@brief` cannot explain what the function does clearly within one sentence, `@details` should be used to supplement it)
- `@remarks` (`@details` is used to explain the meaning and purpose of the function, while `@remarks` is used to mark possible misuse, calling contexts that are already known by default, or detail information that programmers need to be aware of. Do not aggressively mark such information; do not mark it unless the user considers it necessary, or this design explicitly requires it)
- `@private` (non-public functions also require docstrings, and `@private` must be used at the very beginning of the docstring to explicitly mark it as a non-public function)
An example is shown below:
```c
/**
* @brief Do foo bar.
* @details
* A brown fox jumps over a lazy dog.
* Another brown fox jumps over a lazy dog.
* @param[in] in_a Example input parameter.
* @param[in] in_b Example input parameter.
* @param[out] out_c Example output parameter.
* @return Example return value.
*/
int FlFooBar(OMRF_IN(int) in_a, OMRF_IN(int) in_b, OMRF_OUT(int) out_c);
```
### Object Docstring
A docstring must be written for every object, including class (C++ only) and struct (C or C++).
The docstring must contain:
- `@brief`
The docstring may optionally contain:
- `@details` (used in the same way as in the function docstring)
- `@remarks` (used in the same way as in the function docstring)
- `@private` (used in the same way as in the function docstring)
An example is shown below:
```c++
/**
* @brief Foo bar struct example.
* @details
* A brown fox jumps over a lazy dog.
* Another brown fox jumps over a lazy dog.
*/
struct FooBar1 {
// Contents omitted...
};
/**
* @brief Foo bar class example.
* @details
* A brown fox jumps over a lazy dog.
* Another brown fox jumps over a lazy dog.
*/
class FooBar2 {
// Contents omitted...
};
```
### Type Docstring
A docstring must be written for every type, including type alias (C++ only) and typedef (C only).
The docstring must contain:
- `@brief`
The docstring may optionally contain:
- `@details` (used in the same way as in the function docstring)
- `@remarks` (used in the same way as in the function docstring)
- `@private` (used in the same way as in the function docstring)
An example is shown below:
```c++
/**
* @brief Foo bar type 1 example.
* @details
* A brown fox jumps over a lazy dog.
* Another brown fox jumps over a lazy dog.
*/
typedef int FooBarType1;
/**
* @brief Foo bar type 2 example.
* @details
* A brown fox jumps over a lazy dog.
* Another brown fox jumps over a lazy dog.
*/
using FooBarType2 = int;
```
### Constant Docstring
A docstring must be written for every constant, including constexpr (C++ only) and const (C only).
The docstring must contain:
- `@brief`
The docstring may optionally contain:
- `@details` (used in the same way as in the function docstring)
- `@remarks` (used in the same way as in the function docstring)
- `@private` (used in the same way as in the function docstring)
An example is shown below:
```c++
/**
* @brief Foo bar constant 1 example.
* @details
* A brown fox jumps over a lazy dog.
* Another brown fox jumps over a lazy dog.
*/
static const int FOO_BAR_CONST1 = 1;
/**
* @brief Foo bar constant 2 example.
* @details
* A brown fox jumps over a lazy dog.
* Another brown fox jumps over a lazy dog.
*/
constexpr FOO_BAR_CONST2 = 1;
```
### Enum Docstring
A docstring must be written for every enum, including `enum class` (C++ only) and the traditional type-plus-constant style (C only).
We do not write docstrings for the `enum` keyword itself, because in this design we implement enums in C using the type-plus-constant style instead of the `enum` keyword. This decision is already described in the header writing section, so it is not repeated here.
Both the enum type itself and every entry of the enum must have a docstring.
The docstring must contain:
- `@brief`
The docstring may optionally contain:
- `@details` (used in the same way as in the function docstring)
- `@remarks` (used in the same way as in the function docstring)
An example is shown below:
```c++
/**
* @brief Foo bar enum class example.
* @details
* A brown fox jumps over a lazy dog.
* Another brown fox jumps over a lazy dog.
*/
enum class FlFooBar : uint32_t {
/**
* @brief Foo bar variant 1.
*/
Variant1 = 0u,
/**
* @brief Foo bar variant 2.
*/
Variant2 = 1u
};
/**
* @brief Foo bar legacy enum example.
* @details
* A brown fox jumps over a lazy dog.
* Another brown fox jumps over a lazy dog.
*/
typedef uint32_t FlFooBar;
/**
* @brief Foo bar variant 1.
*/
static const FlFooBar FL_FOO_BAR_VARIANT1 = 0u;
/**
* @brief Foo bar variant 2.
*/
static const FlFooBar FL_FOO_BAR_VARIANT2 = 1u;
```
### Member Docstring
A docstring must be written for every member of an object, including the members of struct and class.
The docstring must contain:
- `@brief`
The docstring may optionally contain:
- `@details` (used in the same way as in the function docstring)
- `@remarks` (used in the same way as in the function docstring)
An example is shown below:
```c++
// The docstring of the struct is omitted...
struct FooBar {
/**
* @brief Foo bar struct member example.
* @details
* A brown fox jumps over a lazy dog.
* Another brown fox jumps over a lazy dog.
*/
int ident;
// Other contents omitted...
};
// The docstring of the class is omitted...
class FooBar {
/**
* @brief Foo bar class member example.
* @details
* A brown fox jumps over a lazy dog.
* Another brown fox jumps over a lazy dog.
*/
int ident;
// Other contents omitted...
};
```
### Namespace Docstring
A docstring must be written for every namespace (C++ only).
The docstring must contain:
- `@brief`
The docstring may optionally contain:
- `@details` (used in the same way as in the function docstring)
- `@remarks` (used in the same way as in the function docstring)
An example is shown below:
```c++
/**
* @brief Foo bar namespace example.
* @details
* A brown fox jumps over a lazy dog.
* Another brown fox jumps over a lazy dog.
*/
namespace foobar {
// Contents omitted...
} // namespace foobar
```
### File Docstring
A file-level docstring must be written at the beginning of the file.
The docstring must contain:
- `@file`
- `@brief`
The docstring may optionally contain:
- `@details` (used in the same way as in the function docstring)
- `@remarks` (used in the same way as in the function docstring)
- `@author`
- `@email`
- `@version` (represents the version of the FFI library that this header file corresponds to)
- `@date` (represents the date when this header file was generated)
- `@license`
An example is shown below:
```c
/**
* @file foobar.h
* @brief Foo Bar.
* @details
* A brown fox jumps over a lazy dog.
* Another brown fox jumps over a lazy dog.
*/
```
## Special Notes
<!-- TODO: This section is WIP and need improvements. -->
When the following situations occur, additional requirements apply to the corresponding docstring annotations.
### Pointer Nullability
When a parameter carries a pointer, the `@param` annotation of that parameter must state whether the pointer could be NULL (for output) or whether passing NULL is allowed (for input).
Note that the pointer mentioned here refers to the case where the type decorated by `OMRF_IN` or `OMRF_OUT` is itself a pointer type. Since every output parameter is passed by pointer, the pointer mentioned above does not refer to that pointer created by the output decoration.
### String Lifetime
When passing a string or a string list as parameters, the `@param` annotation of these parameters must state that they become invalid after the next call (for output), or that they no longer need to be kept valid once the function returns (for input).
### Opaque Struct Ownership
The ownership of an opaque struct must be clearly stated in the `@remarks` of the functions that operate on it.
In the `@remarks` of the function that creates an opaque struct, you must additionally state which function can destroy the created object. If an opaque struct has multiple functions that can consume its ownership, for example a normal destroy function and a function that consumes its ownership and returns new data, you only need to mark the normal destroy function.
The ownership annotations of opaque structs are usually concentrated in the C header files, because in the C++ header files every opaque struct is wrapped into a C++ class and the ownership transfer is described by the C++ semantics. Only when the C++ semantics cannot describe it is the `@remarks` annotation required.
### Other Ownership Relationships
Besides opaque structs, there may be other ownership relationships passed across the FFI boundary. These ownership relationships must also be clearly stated, but you need to discover the functions involved by yourself.