> For the complete documentation index, see [llms.txt](https://book.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://book.bsdcn.org/man/man9/style.9.md).

# style.9

`style` — 内核源文件风格指南

## 描述

本文件指定了 FreeBSD 源码树中内核源文件的首选风格。它也是首选用户态代码风格的指南。首选行宽为 80 个字符，但当稍长的行更清晰或更易读时，会有一些例外。任何经常被 grep 搜索的内容，如诊断、错误或 panic 消息，不应因此规则而跨多行拆分。许多风格规则隐含在示例中。在假设 `style` 对某个问题保持沉默之前，请仔细检查示例。

```sh
/*
 * FreeBSD 风格指南。基于 CSRG 的 KNF（Kernel Normal Form）。
 */
/*
 * 非常重要的单行注释看起来像这样。
 */
/* 大多数单行注释看起来像这样。 */
// 虽然它们可能看起来像这样。
/*
 * 多行注释看起来像这样。把它们写成真正的句子。
 * 填充它们，使其看起来像真正的段落。
 */
```

C++ 注释可用于 C 和 C++ 代码。单行注释在文件内应一致地使用 C 或 C++ 风格。多行注释也应一致地使用 C 或 C++ 风格，但可以与单行注释不同。

版权头部应是如下所示的多行注释：

```sh
/*
 * Copyright (c) 1984-2025 John Q. Public
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */
```

从非第一列开始的注释从不被视为许可证声明。在适当的 SPDX-License-Identifier 之前写版权行。如果版权声明包含"`All Rights Reserved`"短语，它应与"`Copyright`"一词在同一行。不应在旧版权行和此短语之间插入新版权行。相反，应在已有的"`All Rights Reserved`"行之后插入新版权短语。进行更改时，将"`All Rights Reserved`"行与每个"`Copyright`"行折叠是可以接受的。对于"`All Rights Reserved`"行与"`Copyright`"一词在同一行上的文件，新版权声明应最后添加。仅在进行实质性更改时才应添加新的"`Copyright`"行，而不是为琐碎的更改添加。

在任何版权和许可证注释之后，有一个空行。非 C/C++ 源文件遵循上面的示例，而 C/C++ 源文件遵循下面的示例。版本控制系统 ID 标签在文件中只应存在一次（不像本文件）。从其他地方获取的文件中的所有 VCS（版本控制系统）修订标识都应保留，包括在适用的情况下显示文件历史的多个 ID。通常，不要编辑外来的 ID 或其基础设施。除非另有包装（如"`#if defined(LIBC_SCCS)`"），否则将两者都包含在"`#if 0 ... #endif`"中以隐藏任何不可编译的位，并使 ID 不出现在目标文件中。仅在文件被重命名时才在外来 VCS ID 前添加"`From:` "。如果文件派生自另一个 FreeBSD 文件，则添加"`From:` "和 FreeBSD git 哈希及完整路径名，并包含原始文件的相关版权信息。

在头文件之前留一个空行。

内核包含文件（`sys/*.h`）排在最前面。如果需要

```c
#include <sys/types.h>
```

或

```c
#include <sys/param.h>
```

则在其他包含文件之前包含它。（

```c
#include <sys/param.h>
```

包含了

```c
#include <sys/types.h>
```

不要两者都包含。）接下来，如果需要，包含

```c
#include <sys/systm.h>
```

其余的内核头文件应按字母顺序排序。

```sh
#include <sys/types.h>	/* 尖括号中的非本地包含。 */
#include <sys/systm.h>
#include <sys/endian.h>
#include <sys/lock.h>
#include <sys/queue.h>
```

对于网络程序，将网络包含文件放在接下来。

```sh
#include <net/if.h>
#include <net/if_dl.h>
#include <net/route.h>
#include <netinet/in.h>
#include <protocols/rwhod.h>
```

不要在内核中包含 **`/usr/include`** 中的文件。

在下一组之前留一个空行，即 **`/usr/include`** 文件，应按名称字母顺序排序。

```sh
#include <stdio.h>
```

全局路径名定义在

```c
#include <paths.h>
```

程序本地的路径名放在本地目录中 "" `pathnames.h` 的双引号中。

```sh
#include <paths.h>
```

在本地包含文件之前留另一个空行。

```sh
#include "pathnames.h"		/* 双引号中的本地包含。 */
```

除非是实现应用程序接口，否则不要在实现命名空间中 `#define` 或声明名称。

"不安全"宏（有副作用的宏）的名称和用于明显常量的宏名称都使用大写。类表达式的宏的展开要么是单个标记，要么有外层括号。在 `#define` 和宏名称之间放一个空格或制表符，但在文件内保持一致。如果宏是函数的内联展开，函数名全小写，宏同名全大写。右对齐反斜杠；这使阅读更容易。如果宏封装了复合语句，将其包含在 `do` 循环中，以便可以安全地在 `if` 语句中使用。任何最终的语句终止分号应由宏调用提供而不是宏本身，以便于美化打印器和编辑器解析。

```sh
#define	MACRO(x, y) do {						e
	variable = (x) + (y);						e
	(y) += 2;							e
} while (0)
```

当代码使用 `#ifdef` 或 `#if` 条件编译时，可以在匹配的 `#endif` 或 `#else` 之后添加注释，以使读者能够轻松辨别条件编译代码区域的结束。此注释仅应用于（主观上）较长的区域、大于 20 行的区域，或一系列嵌套的 `#ifdef` 可能令读者困惑的地方。注释应与 `#endif` 或 `#else` 用单个空格分隔。对于较短的条件编译区域，不应使用结束注释。

`#endif` 的注释应匹配相应 `#if` 或 `#ifdef` 中使用的表达式。`#else` 和 `#elif` 的注释应匹配前面 `#if` 和/或 `#elif` 语句中使用的表达式的逆。在注释中，子表达式"`defined(FOO)`"缩写为"`FOO`"。就注释而言，"`#ifndef` `FOO`"被视为"`#if` `!defined(FOO)`"。

```sh
#ifdef KTRACE
#include <sys/ktrace.h>
#endif
#ifdef COMPAT_43
/* 这里是一个大区域，或其他条件代码。 */
#else /* !COMPAT_43 */
/* 或者这里。 */
#endif /* COMPAT_43 */
#ifndef COMPAT_43
/* 这里是另一个大区域，或其他条件代码。 */
#else /* COMPAT_43 */
/* 或者这里。 */
#endif /* !COMPAT_43 */
```

项目偏好使用 ISO/IEC 9899:1999（"ISO C99"）形式的 `uintXX_t` 无符号整数标识符，而不是旧 BSD 风格的 `u_intXX_t` 形式的整数标识符。新代码应使用前者，如果在该区域正在进行其他重大工作且没有优先选择旧 BSD 风格的压倒性理由，旧代码应转换为新形式。与空白提交一样，应注意仅进行 `uintXX_t` 转换的提交。

类似地，项目偏好使用 ISO C99 的 `bool` 而不是旧的 `int` 或 `boolean_t`。新代码应使用 `bool`，旧代码在合理的情况下可以转换。字面值命名为 `true` 和 `false`。这些比旧拼写 `TRUE` 和 `FALSE` 更受偏好。用户态代码应包含

```c
#include <stdbool.h>
```

而内核代码应包含

```c
#include <sys/types.h>
```

同样，项目在有意义时偏好使用 ISO C99 指定初始化器。

枚举值全部大写。

```sh
enum enumtype { ONE, TWO } et;
```

在标识符中偏好使用内部下划线而不是 camelCase 或 TitleCase。

在声明中，不要在星号和相邻标记之间放置任何空白，但与类型相关的标记除外。（这些标记是基本类型的名称、类型限定符和除正在声明的 `typedef` 名称以外的 `typedef` 名称。）使用单个空格将这些标识符与星号分隔。

在结构中声明变量时，按用途排序，然后按大小（从大到小），再按字母顺序声明它们。第一个类别通常不适用，但也有例外。每个变量占一行。尝试使用一个或两个制表符（根据你的判断）对齐成员名称，使结构可读。仅当用一个制表符足以对齐至少 90% 的成员名称时才应使用一个制表符。跟随极长类型的名称应用单个空格分隔。

主要结构应在其使用的文件顶部声明，或者在多个源文件中使用时放在单独的头文件中。结构的使用应通过单独的声明，如果在头文件中声明则应为 `extern`。

```sh
struct foo {
	struct foo	*next;		/* 活动 foo 的列表。 */
	struct mumble	amumble;	/* mumble 的注释。 */
	int		bar;		/* 尝试对齐注释。 */
	struct verylongtypename *baz;	/* 不适合 2 个制表符。 */
};
struct foo *foohead;			/* 全局 foo 列表的头。 */
```

尽可能使用 [queue(3)](/man/misc/queue.3.md) 宏而不是自己编写列表。因此，前面的示例最好写成：

```sh
#include <sys/queue.h>
struct foo {
	LIST_ENTRY(foo)	link;		/* 对 foo 列表使用队列宏。 */
	struct mumble	amumble;	/* mumble 的注释。 */
	int		bar;		/* 尝试对齐注释。 */
	struct verylongtypename *baz;	/* 不适合 2 个制表符。 */
};
LIST_HEAD(, foo) foohead;		/* 全局 foo 列表的头。 */
```

避免对结构类型使用 typedef。typedef 有问题，因为它们不能正确隐藏其底层类型；例如你需要知道 typedef 是结构本身还是指向结构的指针。此外，它们必须声明一次，而不完整的结构类型可以根据需要多次提及。typedef 在独立头文件中难以使用：定义 typedef 的头文件必须在使用它的头文件之前包含，或者由使用它的头文件包含（这会导致命名空间污染），或者必须有获取 typedef 的后门机制。

当约定需要 `typedef` 时，使其名称与结构标签匹配。避免以"`_t`"结尾的 typedef，除非 Standard C 或 POSIX 指定。

```sh
/* 使结构名称匹配 typedef。 */
typedef	struct bar {
	int	level;
} BAR;
typedef	int		foo;		/* 这是 foo。 */
typedef	const long	baz;		/* 这是 baz。 */
```

所有函数都在某处有原型。

私有函数（即不在其他地方使用的函数）的函数原型放在第一个源模块的顶部。一个源模块本地的函数应声明为 `static`。

从内核其他部分使用的函数在相关的包含文件中有原型。函数原型应按逻辑顺序列出，最好按字母顺序，除非有令人信服的理由使用不同的顺序。

在多个模块中本地使用的函数放在单独的头文件中，例如 "" `extern.h`。

内核有与参数类型关联的名称，例如，在内核中使用：

```sh
void	function(int fd);
```

在对用户态应用程序可见的头文件中，可见的原型必须使用"受保护"的名称（以下划线开头的名称）或使用不带名称的类型。优先使用受保护的名称。例如，使用：

```sh
void	function(int);
```

或：

```sh
void	function(int _fd);
```

原型在制表符后可以有额外的空格，以使函数名称对齐：

```sh
static char	*function(int _arg, const char *_arg2, struct foo *_arg3,
		    struct bar *_arg4);
static void	 usage(void);
/*
 * 所有主要例程都应有注释，简要描述它们做什么。
 * "main" 例程之前的注释应描述程序做什么。
 */
int
main(int argc, char *argv[])
{
	char *ep;
	long num;
	int ch;
```

为保持一致性，应使用 getopt(3) 解析选项。选项应在 getopt(3) 调用和 `switch` 语句中排序，除非 `switch` 的部分级联。`switch` 语句中执行一些代码然后级联到下一个 case 的元素应有 `FALLTHROUGH` 注释。数值参数应检查准确性。由于非显而易见的原因不可达的代码可以标记 /\* `NOTREACHED` \*/。

```sh
	while ((ch = getopt(argc, argv, "abNn:")) != -1)
		switch (ch) {		/* 缩进 switch。 */
		case 'a':		/* 不缩进 case。 */
			aflag = 1;	/* case 体缩进一个制表符。 */
			/* FALLTHROUGH */
		case 'b':
			bflag = 1;
			break;
		case 'N':
			Nflag = 1;
			break;
		case 'n':
			num = strtol(optarg, &ep, 10);
			if (num <= 0 || *ep != 'e0') {
				warnx("illegal number, -n argument -- %s",
				    optarg);
				usage();
			}
			break;
		case '?':
		default:
			usage();
		}
	argc -= optind;
	argv += optind;
```

关键字（`if`、`while`、`for`、`return`、`switch`）后加空格。单行语句允许两种花括号（`{` 和 `}`）风格。要么用于所有单语句，要么仅在需要清晰度时使用。函数内的使用应一致。无限循环使用 `for` 而不是 `while`。

```sh
	for (p = buf; *p != 'e0'; ++p)
		;	/* nothing */
	for (;;)
		stmt;
	for (;;) {
		z = a + really + long + statement + that + needs +
		    two + lines + gets + indented + four + spaces +
		    on + the + second + and + subsequent + lines;
	}
	for (;;) {
		if (cond)
			stmt;
	}
	if (val != NULL)
		val = realloc(val, newsize);
```

`for` 循环的某些部分可以留空。

```sh
	for (; cnt < 15; cnt++) {
		stmt1;
		stmt2;
	}
```

`for` 循环可以声明并初始化其计数变量。

```sh
	for (int i = 0; i < 15; i++) {
		stmt1;
	}
```

缩进是 8 字符制表符。第二级缩进是四个空格。如果必须换行长语句，将运算符放在行尾。

```sh
	while (cnt < 20 && this_variable_name_is_too_long &&
	    ep != NULL)
		z = a + really + long + statement + that + needs +
		    two + lines + gets + indented + four + spaces +
		    on + the + second + and + subsequent + lines;
```

不要在行尾添加空白，仅使用制表符后跟空格来形成缩进。不要使用比制表符产生的更多空格，也不要在制表符前使用空格。

闭合和开花括号与 `else` 在同一行。不必要的花括号可以省略。

```sh
	if (test)
		stmt;
	else if (bar) {
		stmt;
		stmt;
	} else
		stmt;
```

函数名后无空格。逗号后有空格。`(` 或 `[` 后无空格，`]` 或 `)` 前无空格。

```sh
	error = function(a1, a2);
	if (error != 0)
		exit(error);
```

一元运算符不需要空格，二元运算符需要。除非为了优先级需要或语句没有它们会令人困惑，否则不要使用括号。记住其他人可能比你更容易困惑。你理解以下内容吗？

```sh
	a = b->c[0] + ~d == (e || f) || g && h ? i : j >> 1;
	k = !(l & FLAGS);
```

退出应在成功时为 0，失败时为 1。

```sh
	exit(0);	/*
			 * 避免明显的注释，如
			 * "成功时退出 0。"
			 */
}
```

函数类型应单独一行，位于函数之前。函数体的开花括号应单独一行。

```sh
static char *
function(int a1, int a2, float fl, int a4, struct bar *bar)
{
```

在函数中声明变量时，按大小排序，然后按字母顺序；每行多个可以。如果行溢出，重用类型关键字。变量可以在声明时初始化，特别是当它们在作用域的其余部分是常量时。声明可以在任何块中，但必须放在语句之前。初始化变量时应避免调用复杂函数。

```sh
	struct foo one, *two;
	struct baz *three = bar_get_baz(bar);
	double four;
	int *five, six;
	char *seven, eight, nine, ten, eleven, twelve;
	four = my_complicated_function(a1, f1, a4);
```

不要在其他函数内声明函数；ANSI C 说此类声明具有文件作用域，无论声明的嵌套如何。在看似本地作用域中隐藏文件声明是不可取的，会引起好的编译器的投诉。

类型转换和 `sizeof` 后不跟空格。`sizeof` 总是带括号编写。冗余括号规则不适用于 `sizeof var` 实例。

`NULL` 是首选的空指针常量。在编译器知道类型的上下文中（例如在赋值中），使用 `NULL` 而不是 `(type *)0` 或 `(type *)NULL`。在其他上下文中，特别是对于所有函数参数，使用 `(type *)NULL`。（对于可变参数，类型转换是必需的，如果函数原型可能不在作用域内，对于其他参数也是必需的。）用 `NULL` 测试指针，例如，使用：

```sh
(p = f()) == NULL
```

而不是：

```sh
!(p = f())
```

不要在没有比较的情况下测试，或使用一元 `!`（布尔值除外）。例如，使用：

```sh
if (*p == 'e0')
```

而不是：

```sh
if (!*p)
```

偏好：

```sh
if (count != 0)
```

而不是：

```sh
if (count)
```

返回 `void *` 的例程不应将其返回值转换为任何指针类型。

`return` 语句中的值应括在括号中。

使用 err(3) 或 warn(3)，不要自己编写。

```sh
	if ((four = malloc(sizeof(struct foo))) == NULL)
		err(1, (char *)NULL);
	if ((six = (int *)overflow()) == NULL)
		errx(1, "number overflowed");
	return (eight);
}
```

不要使用 K\&R 风格的声明或定义，它们已过时，在 C23 中被禁止。编译器会警告它们的使用，一些默认将它们视为错误。将 K\&R 风格定义转换为 ANSI 风格时，保留关于参数的任何注释。

长参数列表使用正常的四空格缩进换行。

可变数量参数应如下所示：

```sh
#include <stdarg.h>
void
vaf(const char *fmt, ...)
{
	va_list ap;
	va_start(ap, fmt);
	STUFF;
	va_end(ap);
	/* void 函数不需要返回。 */
}
static void
usage(void)
{
```

函数应先有局部变量声明，后跟一个空行，然后是第一条语句。如果没有声明局部变量，第一行应为语句。旧版本的此 `style` 文档要求代码前有空行。在对代码进行重大更改时，应删除此类行。

使用 printf(3)，而不是 fputs(3)、puts(3)、putchar(3) 等；它更快且通常更干净，更不用说避免愚蠢的错误。

用法语句应看起来像手册页的 SYNOPSIS。用法语句应按以下顺序构造：

* 没有操作数的选项排在前面，按字母顺序，在单组方括号（`[` 和 `]`）中。
* 带操作数的选项接下来，也按字母顺序，每个选项及其参数在自己的方括号对中。
* 必需参数（如果有）接下来，按在命令行上应指定的顺序列出。
* 最后，任何可选参数应列出，按应指定的顺序列出，全部在方括号中。

竖线（`|`）分隔"二选一"选项/参数，多个一起指定的选项/参数放在单组方括号中。

```sh
"usage: f [-aDde] [-b b_arg] [-m m_arg] req1 req2 [opt1 [opt2]]en"
"usage: f [-a | -b] [-c [-dEe] [-n number]]en"
```

```sh
	(void)fprintf(stderr, "usage: f [-ab]en");
	exit(1);
}
```

注意，手册页选项描述应按纯字母顺序列出选项。也就是说，不考虑选项是否接受参数。字母顺序应考虑上述大小写顺序。

只要可能，代码应通过代码检查器（例如各种静态分析器或 `cc` `-Wall`）运行，并产生最少的警告。

新代码应使用 `_Static_assert` 而不是旧的 `CTASSERT`。

`__predict_true` 和 `__predict_false` 仅应在使代码可测量地更快时用于频繁执行的代码。对不频繁运行的代码（如子系统初始化）进行预测是浪费的。使用分支预测提示时，非典型错误条件应使用 `__predict_false`（记录例外）。几乎总是成功的操作使用 `__predict_true`。仅对整个 if 语句使用注释，而不是单个子句。没有分支可能性的经验证据，不要添加这些注释。

新的核心内核代码应符合 `cc` 指南。第三方维护的模块和设备驱动程序的指南更宽松。预期它们的代码至少在风格上内部一致。

风格更改（包括空白更改）会使下游消费者的工作复杂化，并可能损害开发者跟踪某些更改历史的能力。必须避免此类独立更改，并且不应跨越不相关的目录，因为这会增加合并到 stable 和 release 分支（MFC）时冲突的机会。另一方面，当某个逻辑代码单元（无论是函数、函数组、文件或文件组）的很大一部分（通常约一半）将被修改时，鼓励开发者按照本文档所述修改整个单元的风格。在这种情况下，对其他未修改代码的风格更改应单独提交。仅风格的提交应添加到源码仓库顶部的 `.git-blame-ignore-revs` 文件中，以将它们从 `git blame` 中隐藏。此文件中的注释指示如何使用它。仓库中大约符合 FreeBSD KNF `cc` 的代码不得偏离合规性。

### C++

KNF 风格最初定义为 C 的风格。C++ 引入了几个新习惯用法，这些在 KNF C 中没有现成的对应，例如类中的内联函数定义。C++ 也不总是与某些 KNF 指南兼容，例如将返回值括在括号中。对于 C++ 代码，FreeBSD 旨在遵循广泛接受的 C++ 实践，同时遵循 KNF 的一般形状。本节列举了与 KNF C 不同的 C++ 特定指南。

C++ 源文件的首选后缀是".cc"和".hh"。头文件应始终使用后缀，与 C++ 标准库的头文件不同。

返回值不应括在括号中。将现有 C 代码转换为 C++ 时，现有返回值可以保留在括号中。

命名空间声明的开花括号应在第一行，类似于结构和类定义。嵌套命名空间应使用单个命名空间声明声明。

```sh
namespace foo::bar {
}
```

成员函数声明应遵循与独立函数原型相同的风格，但函数返回类型和名称之间应使用空格。

顶层的函数定义应在函数类型后使用换行，类似于 C 函数定义。

类、结构或联合内的嵌套成员函数定义不应在函数类型后使用换行。相反，这些应遵循成员函数声明的风格。这是更常见的 C++ 风格，对于小方法（如 getter 和 setter）更紧凑。

体由单个语句组成的内联函数可以为函数体使用单行。体为空的内联函数应始终使用单行。

```sh
struct widget {
	int foo() { return 4; }
	int bar();
};
int
widget::bar()
{
	return 6;
}
```

默认和删除的方法应声明为单行。

```sh
class box {
	~box() = default;
};
```

在模板声明中，`template` 关键字和模板参数列表后应在模板声明之前换行。

```sh
template <typename T>
class box {
	T data;
};
```

引用变量的 `&` 应放在变量名上而不是类型上，类似于指针使用 `*` 的风格。

```sh
	int x;
	int &xp = x;
```

变量可以在函数内的任何位置声明，而不仅仅在块的开头。

应优先使用标准库容器而不是 [queue(3)](/man/misc/queue.3.md) 或 [tree(3)](/man/misc/tree.3.md) 宏。

应使用 `nullptr` 而不是 `NULL` 或 0。

使用标准库类型管理字符串，如 `std::string` 和 `std::string_view`，而不是 `char *` 和 `const char *`。与 C 代码交互时可以使用 C 类型。

`auto` 关键字可以在各种提高可读性的上下文中使用。示例包括迭代器、范围 for 值的非平凡类型以及明显类型的返回值，如 `static_cast` 或 `std::make_unique`。将任何限定符放在 `auto` 之前，例如：`const auto`。

使用 `std::unique_ptr` 和 `std::shared_ptr` 智能指针管理动态分配对象的生命周期，而不是 `new` 和 `delete`。使用 `std::make_unique` 或 `std::make_shared` 构造智能指针。除非必要与 C 代码交互，否则不要使用 malloc(3)。

不要在头文件的全局作用域中使用 `using` 导入任何命名空间。除 `std` 命名空间（例如 `std::literals`）以外的命名空间可以在源文件和头文件的函数作用域中导入。

使用 `using` 而不是 `typedef` 定义类型别名。

## 文件

**`/usr/src/tools/build/checkstyle9.pl`** 检查源文件中 `cc` 违规的脚本。

**`/usr/src/tools/tools/editing/freebsd.el`** 遵循 FreeBSD `cc` 缩进规则的 Emacs 插件。

**`/usr/src/tools/tools/editing/freebsd.vim`** 遵循 FreeBSD `cc` 缩进规则的 Vim 插件。

## 参见

indent(1), err(3), warn(3), [style.Makefile(5)](https://github.com/FreeBSD-Ask/freebsd-man-sc/tree/main/man5/style.makefile.5.md), [style.mdoc(5)](/man/man5/style.mdoc.5.md), [style.lua(9)](/man/man9/style.lua.9.md)

## 历史

本手册页最初基于 4.4BSD 发行版中的 `src/admin/style/style` 文件，并经常更新以反映 FreeBSD 项目的当前实践和愿望。`src/admin/style/style` 是 CSRG 对 Ken Thompson 和 Dennis Ritchie 在 Version 6 AT\&T UNIX 中编程风格的编纂。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://book.bsdcn.org/man/man9/style.9.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
