如需详细了解 FIDL 的整体目标、目标和要求, 请参阅概念概览。
核心概念
消息
FIDL 消息是数据的集合。
该消息是一个连续的结构,由单个 内嵌主要对象,后跟零个或多个 脱线次要对象。
对象按遍历顺序存储,并会根据内边距进行填充。
主要对象和次要对象
第一个对象称为“主要对象”。 它是一个具有固定大小的结构,其类型和大小可从 上下文。阅读消息时,必须知道预期 即格式不是自描述格式。背景信息 应该能够明确说明相应情况例如 在将消息作为 IPC 的一部分读取的情况下 (请参阅事务性消息标头), 上下文由标头中包含的数据完全指定 (特别是,序数可让收件人知道 预期类型)。要读取静态数据 但假定编码器和解码器 了解正在编码或解码的类型(例如, 系统会将这些信息编译到 编码器和解码器)。
主要对象可以指次要对象(例如 例如字符串、向量、并集等)。 或可选数据是必填项
次要对象以遍历顺序脱行存储。
主要对象和次要对象都是 8 字节对齐的, 无间断(对齐所需的除外)。
主要对象及其次要对象统称为 消息。
交易消息
事务性 FIDL 消息(事务性消息)用于 将数据从一个应用发送到另一个应用
事务性消息部分介绍了如何 事务性消息由可选的标头消息组成 。
遍历顺序
消息的遍历顺序由递归深度优先原则决定 它包含的所有对象的步行,可通过沿着链获得 引用。
采用以下结构:
type Cart = struct {
items vector<Item>;
};
type Item = struct {
product Product;
quantity uint32;
};
type Product = struct {
sku string;
name string;
description string:optional;
price uint32;
};
Cart
消息的深度优先遍历顺序由以下代码定义
伪代码:
visit Cart:
for each Item in Cart.items vector data:
visit Item.product:
visit Product.sku
visit Product.name
visit Product.description
visit Product.price
visit Item.quantity
双形式:编码与解码
相同的邮件内容可以用以下两种形式之一表示: 即经过编码和解码。 它们具有相同的尺寸和整体布局,但它们 指针(内存地址)或句柄(功能)的表示形式。
FIDL 设计为可以对消息进行编码和解码 都保存在内存中
消息编码是规范的,因为消息中只有一个编码。 特定消息
已编码的消息
经过编码的消息已已准备好转移到另一个进程:它 不包含指针(内存地址)或句柄(功能)。
在编码期间...
- 邮件中指向子对象的所有指针都替换为 指明其所指代词是否存在,
- 邮件中的所有标识名都将提取到关联的标识名中 vector,并被替换为指示其所引用对象是否为 是否存在。
然后,系统会将生成的经过编码的消息和句柄矢量发送到 使用 zx_channel_write() 或类似 IPC 的其他进程 机制。 此类 IPC 还有其他限制。请参阅 事务性消息。
已解码的消息
已准备可在进程地址中使用的解码消息 空间:它可能包含指针(内存地址)或句柄(功能)。
在解码期间:
- 使用 编码的存在标记和不存在标记。
- 消息中的所有标识名都会从关联的 处理矢量。
生成的解码消息可直接从内存中使用。
内嵌对象
对象还可能包含内联对象,这些内联对象汇总在 所包含对象的正文,例如嵌入式结构体和 结构体。
示例
在以下示例中,Region
结构包含一个向量
Rect
结构,其中每个 Rect
由两个 Point
组成。
每个 Point
均由 x
和 y
值组成。
type Region = struct {
rects vector<Rect>;
};
type Rect = struct {
top_left Point;
bottom_right Point;
};
type Point = struct {
x uint32;
y uint32;
};
按遍历顺序检查对象意味着我们将从
Region
结构体 - 它是主要对象。
rects
成员是 vector
,因此其内容以外部形式存储。
这意味着,vector
内容紧跟在 Region
对象之后。
每个 Rect
结构体都包含两个 Point
,它们以内嵌方式存储
(因为它们的数量是固定的),而每个 Point
的
原始数据类型(x
和 y
)也以内嵌方式存储。
原因都一样成员类型数量是固定的
当从属实例大小时,我们使用内嵌存储空间 对象是固定的,且超出行(包括 盒装结构体)。
类型详细信息
在本部分中,我们将介绍所有 FIDL 对象的编码。
原语
- 以小端字节序格式存储的值。
- 包装自然对齐。
- 每个 m 字节基元都存储在 m 字节边界上。
- 非可选。
支持以下基元类型:
类别 | 类型 |
---|---|
布尔值 | bool |
有符号整数 | int8 、int16 、int32 、int64 |
无符号整数 | uint8 、uint16 、uint32 、uint64 |
IEEE 754 floating-point | float32 、float64 |
字符串 | (非基元,请参阅字符串) |
数字类型的后缀是其大小(以位为单位)。
布尔值类型 bool
存储为单个字节,并且只有
值 0 或 1。
所有浮点值均表示有效的 IEEE 754 位模式。
枚举和位
位字段和枚举存储为其底层基元
类型(例如uint32
)。
句柄
句柄是一个 32 位整数,但经过特殊处理。 在编码以进行传输时,句柄的传输表示形式会替换为 存在和不存在指示,而句柄本身存储在 单独的句柄矢量。解码后,句柄存在状态指示为 替换为零(如果不存在)或有效句柄(如果有)。
标识名值本身不会从一个应用转移到 另一个。
在这方面,手柄就像指针一样它们会引用 都是独一无二的 句柄从一个应用的上下文移至另一个应用的上下文。
值 0 可用于表示缺少可选句柄1。
如需查看有关将标识名转移过来的详细示例,请参阅标识名的生命周期。 FIDL。
汇总对象
聚合对象充当其他对象的容器。 它们可能会以内联或外行的方式存储这些数据,具体取决于其类型。
数组
- 固定长度的同构元素序列。
- 其元素采用了自然对齐的方式。
- 数组的对齐方式与其元素的对齐方式相同。
- 每个后续元素都会在元素的对齐边界上对齐。
- 该数组的步长正好等于元素的大小( 包含满足元素对齐约束所需的内边距)。
- 一律不可选。
- 布尔值数组没有特殊情况。每个布尔值元素 字节。
数组的表示形式:
array<T, N>
:其中 T 可以是任何 FIDL 类型 (包括数组),N 是数组中的元素数量。 注意:数组的大小不得超过 232-1。 如需了解详情,请参阅 RFC-0059。
矢量
- 可变长度的同构元素序列。
- 可以选填;不存在向量和空向量是不同的。
- 可以指定大小上限,例如
vector<T>:40
最多包含 40 个元素矢量。 - 存储为一条 16 字节的记录,其中包括:
<ph type="x-smartling-placeholder">
- </ph>
size
:64 位无符号元素数 注意:矢量的大小不得超过 232-1。 如需了解详情,请参阅 RFC-0059。data
:64 位存在状态指示或指向外行元素数据的指针
- 在编码以进行传输时,
data
表示 内容: <ph type="x-smartling-placeholder">- </ph>
0
:矢量不存在UINTPTR_MAX
:矢量存在,数据是下一个外行对象
- 在解码以供使用时,
data
是一个 指向内容的链接: <ph type="x-smartling-placeholder">- </ph>
0
:矢量不存在<valid pointer>
:矢量存在,数据位于指定的内存地址
- 布尔值矢量没有特殊情况。每个布尔值元素 字节。
向量表示如下:
vector<T>
:必需的元素类型 T 向量(验证错误)data
缺失时会发生)vector<T>:optional
:元素类型 T 的可选矢量vector<T>:N
、vector<T>:<N, optional>
:最大长度为 N 个元素的矢量
T 可以是任何 FIDL 类型。
字符串
字符串以 uint8
字节的矢量的形式实现,并具有约束条件
这些字节必须是有效的 UTF-8。
结构
一个结构体包含一系列类型化字段。
在内部,该结构具有内边距 所有成员的对齐要求。 在外部,结构在 8 字节边界上对齐,因此可能包含 最终填充以满足该要求。
以下是一些示例。
具有 int32 和 int8 字段的结构体对齐 4 个字节(由于 int32),大小为 8 个字节(int8 之后的 3 个字节填充):
包含 bool 和 string 字段的结构体的对齐方式为 8 个字节 (由于 string 的原因)且大小为 24 个字节(在 bool):
具有 bool 和两个 uint8 字段的结构体的对齐方式为 1 字节 大小为 3 个字节(无填充!):
结构可以是:
- empty 表示其中没有任何字段。此类结构的大小为 1 个字节,
对齐 1 个字节,完全等同于包含
uint8
,值为 0。 - 必需 - 结构的内容内嵌存储。
- 可选 - 结构的内容外行存储 通过间接引用访问
结构的存储取决于其在参照点处是否装箱。
- 非盒装结构:
<ph type="x-smartling-placeholder">
- </ph>
- 内容以内嵌方式存储在其包含类型中, 构建高效的聚合结构。
- 进行内嵌时,结构布局不会更改;其字段不是 重新打包以填补容器中的空白
- 盒装结构:
<ph type="x-smartling-placeholder">
- </ph>
- 内容存储到在线之外,并可通过间接 参考。
- 在编码以进行传输时,存储的引用表示 结构:
0
:引用不存在UINTPTR_MAX
:引用存在,构造内容 是下一个输出行外对象- 在解码以供使用时,存储的引用是一个指针:
0
:引用不存在<valid pointer>
:引用存在,结构内容位于 指示的内存地址
结构体由其声明的名称(例如 Circle
)表示,可以装箱:
Point
:必需Point
box<Color>
:盒装,始终可选Color
以下示例说明了:
- 结构布局(顺序、打包和对齐)
- 必需的结构 (
Point
) - 盒装 (
Color
)
type Circle = struct {
filled bool;
center CirclePoint; // CirclePoint will be stored in-line
radius float32;
color box<Color>; // Color will be stored out-of-line
dashed bool;
};
type CirclePoint = struct {
x float32;
y float32;
};
type Color = struct {
r float32;
g float32;
b float32;
};
Color
内容将填充到 8 字节次要对象对齐边界。
详细介绍布局:
- 第一个成员
filled bool
占用一个字节,但需要三个字节 填充,因为下一个成员采用 4 字节对齐 。 center CirclePoint
成员是一个必需结构体的示例。因此 其内容(x
和y
32 位浮点数)内嵌在内,整个代码 消耗 8 个字节。radius
是一个 32 位内容,需要 4 字节对齐。自下一个 可用位置已位于 4 字节对齐边界上,无填充 为必填字段。color box<Color>
成员就是一个盒装结构的一个示例。由于color
数据不一定会存在,这是最高效的处理方式 这是为了将指针作为内嵌数据保存在该结构中。这样, 如果确实存在color
成员,则该指针将指向其数据 (或者,如果是编码格式,则指示“存在”),并且 数据本身存储外联(在Circle
的数据之后), 结构)。如果color
成员不存在,则指针为NULL
(或者,在编码格式中,通过存储 0 来表示“不存在”)。dashed bool
不需要任何特殊对齐,因此接下来会运行。 不过,现在我们到了对象的末尾,所有对象都必须 8 字节对齐。这意味着我们需要额外的 7 个字节的填充。color
的外联数据遵循Circle
数据结构,以及 包含三个 32 位float
值(r
、g
和b
);需要 4 个 字节对齐,因此可以在没有内边距的情况下相互依存。但是,正如 对于Circle
对象,我们要求对象本身 8 字节对齐,因此需要 4 个字节的填充。
总体而言,此结构需要 48 个字节。
不过,通过将 dashed bool
移到 filled bool
之后,
您可以节省大量空间2:
- 两个
bool
值是“打包” 浪费空间。 - 内边距已缩减至两个字节,因此非常适合
添加一个 16 位值,或者再添加一些
bool
或 8 位整数。 - 请注意,
Color
框之后不需要内边距;所有内容 在 8 字节边界上完全对齐。
该结构现在需要 40 个字节。
信封
信封是数据的容器,供表和联合在内部使用。时间是 且未采用 FIDL 语言。具有固定的 8 字节格式。
全零的信包标头称为“零信包”。它 用于表示不存在的信封。否则,存在信封 其标记的位 0 指示数据以内嵌方式还是非在线方式存储:
- 如果设置了位 0,则使用内嵌表示法。
- 如果未设置位 0,则使用脱机表示法。
只有在有效负载的大小小于等于 4 字节时才能设置位 0。位 0 可以是 仅当信封是零个信封或 载荷 >4 个字节。
有了 num_bytes
和 num_handles
,我们就可以跳过未知的信封内容。
num_bytes
始终是 8 的倍数,因为外行对象
8 字节对齐。
表格
- 由元素数量和指针组成的记录类型。
- 指针指向一个信封数组,其中每个信封都包含一个元素。
- 每个元素都与一个序数相关联。
- 序数是连续的,间隔会产生空信封费用,因此不建议使用。
表由其声明的名称表示(例如,值),且绝不是可选的:
Value
:必需Value
以下示例展示了表如何根据其字段进行布局。
type Value = table {
1: command int16;
2: data Circle;
3: offset float64;
};
联合体
- 由序数和信封组成的记录类型。
- 序数表示成员选择,由 uint64 表示。
- 每个元素均与用户指定的序数相关联。
- 序数是依序排列。与表格不同,序数中的间隙不会产生导线 格式空间成本。
- 不存在可选并集时,会使用
0
序数和零信封来表示。 - 不允许空联合。
联合由其声明的名称(例如 Value
)和可选性表示:
Value
:必需Value
Value:optional
:可选的Value
以下示例展示了联合如何根据其字段进行布局。
type UnionValue = strict union {
1: command int16;
2: data Circle;
3: offset float64;
};
事务性消息
在事务性消息中,始终有一个标头,后跟 可选的 body。
标头和正文都是 FIDL 消息,如上文所定义;即 数据集合。
标头采用以下格式:
zx_txid_t txid
,事务 ID(32 位) <ph type="x-smartling-placeholder">- </ph>
- 具有高位设置的
txid
已预留给以下人员使用: zx_channel_call() - 未设置高位的
txid
已预留以供用户空间使用 txid
的0
值将用于 需要另一方作出响应。 注意:如需详细了解txid
分配,请参阅 zx_channel_call().
- 具有高位设置的
uint8[3] flags
不得通过绑定进行检查。这些标志可用于 以实现电线格式的软过渡。请参阅标头标记 ,了解有关当前标志定义的说明。uint8 magic number
,用于确定两种传输格式是否兼容。uint64 ordinal
- 零序数无效。
- 设置了最高有效位的序数保留 控制消息和未来的扩展。
- 未设置最高有效位的序数表示方法调用 和响应。
事务消息有三种类型:
- 方法请求,
- 方法响应,以及
- 事件请求。
在接下来的几个示例中,我们将使用以下接口:
type DivisionError = strict enum : uint32 {
DIVIDE_BY_ZERO = 1;
};
protocol Calculator {
Add(struct {
a int32;
b int32;
}) -> (struct {
sum int32;
});
Divide(struct {
dividend int32;
divisor int32;
}) -> (struct {
quotient int32;
remainder int32;
}) error DivisionError;
Clear();
-> OnError(struct {
status_code uint32;
});
};
Add() 和 Divide() 方法对方法请求进行了说明 (从客户端发送到服务器),以及一个方法响应 (从服务器发送回客户端)。
Clear() 方法是不
错误的说法是“空”正文:这意味着 header 后面是body。在使用 Clear() 时, 没有 body,只有一个 header。
方法请求消息
接口的客户端向服务器发送方法请求消息 才能调用 方法。
方法响应消息
服务器向客户端发送方法响应消息以表明已完成 方法调用并提供一个(可能为空的)结果。
只有定义为提供(可能为空)结果的双向方法请求 都会引发方法响应。 单向方法请求不得生成方法响应。
方法响应消息提供与先前的方法请求相关联的结果。 邮件正文包含方法结果,就好像这些结果封装在 struct。
在这里,我们看到 912 / 43 的答案是 21,余数为 9。
请注意 1
的 txid
值,此值用于标识交易。
2
的 ordinal
值表示该方法,在本例中为
Divide() 方法。
如下所示,123 + 456
为 579
。
在这里,txid
值现在为 2
,这只是下一笔交易
分配给交易的编号。
ordinal
为 1
,表示 Add()。请注意,结果需要
4 个字节的内边距,以使 body 对象的大小
8 个字节的倍数。
最后,Clear() 方法与 Add() 方法不同,
Divide():
* 它没有正文(即,只包含标头),并且
* 它不会从接口请求响应(txid
为零)。
事件请求
一个事件示例是 Calculator
中的 OnError() 事件。
服务器向客户端发送自发事件请求 以指明发生了异步事件,如 协议声明
在 Calculator
示例中,我们可以想象尝试除以 0
会导致系统发送 OnError() 事件并显示“除以零”状态代码
然后再关闭连接。这样,客户端就可以区分
与因错误而关闭的连接
(如计算器进程异常终止)。
请注意 txid
如何为零(表示这不是交易的一部分),
且 ordinal
为 4
(表示 OnError() 方法)。
body 包含事件参数,就像它们封装在 struct,与方法结果消息一样。 请注意,正文已填充以保持 8 字节对齐。
墓碑(控制消息序号 0xFFFFFFFFFFFFFFFF)
复数是一个事件(txid 零),其序数为 0xFFFFFFFFFFFFFFFF。服务器 在关闭连接前, 可以发送一封摘要信息作为最后一条消息, 提供连接关闭原因的指示。没有其他消息 可在墓碑后通过连接发送。墓碑并非来自 连接到服务器
墓碑的电线表示形式等同于以下 FIDL:
fidl
struct {
error zx.Status;
};
将来可能会在 FIDL 中正式定义墓碑。
详细信息
大小和对齐
sizeof(T)
表示类型为 T 的对象的大小(以字节为单位)。
alignof(T)
表示用于存储类型为 T 的对象的对齐系数(以字节为单位)。
FIDL 基元类型存储在多个
其大小(以字节为单位)。因此,对于基元 T 而言,其值为 alignof(T) ==
sizeof(T)
。这称为自然对齐。它具有
满足现代 CPU 的典型对齐要求的良好属性
架构。
FIDL 复杂类型(例如结构体和数组)存储在
是其所有消息中最大对齐系数的倍数,
字段。因此,对于复杂类型 T,alignof(T) ==
max(alignof(F:T))
会针对 T 中的所有字段 F 执行。它有很好的
属性(可以是
使用生成的代码中的打包属性强制执行的)。复杂大小
type 是存储其成员适当对齐所需的字节总数
最大范围的对齐方式因数。
FIDL 主要对象和次要对象在 无论消息内容如何FIDL 消息的主要对象 从偏移量 0 开始。次要对象,此类对象是 消息中的指针,始终从 8 的倍数的偏移量开始。 (因此,消息中的所有指针都指向 8 的倍数的偏移量)。
FIDL 内嵌对象(嵌入到主要或次要中的复杂类型) 对象)根据其类型对齐。不强制使用 8 个字节 对齐方式。
类型
注意:
- N 表示元素的数量,无论是否明确声明(如
array<T, N>
,包含 N 个类型为 T 元素的数组,或隐式地包含该元素 (由 7 个元素组成的table
将具有N=7
)。 - 行外大小始终填充为 8 个字节。我们会指明 尺寸如下所示(不包括内边距)。
- 以下
vector
条目中的sizeof(T)
为
in_line_sizeof(T) + out_of_line_sizeof(T)
。 - 以下
table
条目中的 M 是当前字段的最大序数。 - 在下面的
struct
条目中,内边距指的是所需的内边距, 使struct
与最宽的元素对齐。例如:struct{uint32;uint8}
包含 3 个字节的填充,这与 填充,以与 8 个字节的边界对齐。
类型 | 尺寸(内嵌) | 大小(非在线) | 对齐方式 |
---|---|---|---|
bool |
1 | 0 | 1 |
int8 、uint8 |
1 | 0 | 1 |
int16 、uint16 |
2 | 0 | 2 |
int32 、uint32 、float32 |
4 | 0 | 4 |
int64 、uint64 、float64 |
8 | 0 | 8 |
enum 、bits |
(底层类型) | 0 | (底层类型) |
handle 等。 |
4 | 0 | 4 |
array<T, N> |
sizeof(T) * N | 0 | 对齐 |
vector 等。 |
16 | N * sizeof(T) | 8 |
struct |
求和(sizeof(fields)) + 填充 | 0 | 8 |
box<struct> |
8 | 求和(sizeof(fields)) + 填充 | 8 |
envelope |
8 | sizeof(字段) | 8 |
table |
16 | M * sizeof(envelope) +sum(aligned_to_8(sizeof(当前字段))) | 8 |
union 、union:optional |
16 | sizeof(所选变体) | 8 |
上面的 handle
条目是指所有类型的句柄,具体来说,
handle
、handle:optional
、handle:H
、handle:<H, optional>
、
client_end:Protocol
、client_end:<Protocol, optional>
、
server_end:Protocol
和 server_end:<Protocol, optional>
。
同样,上面的 vector
条目是指所有类型的向量,
具体而言,vector<T>
、vector<T>:optional
、vector<T>:N
、
vector<T>:<N, optional>
、string
、string:optional
、string:N
和
string:<N, optional>
。
内边距
消息的创建者必须用零填充所有对齐填充间隙。
消息的使用者必须验证填充是否包含零(并生成 否则将抛出错误)。
最大递归深度
FIDL 矢量、可选结构、表和联合支持 递归消息。如果未选中,处理过于深层的消息 或导致资源耗尽,或造成无法检测到的无限循环。
为安全起见,所有 FIDL 消息的最大递归深度限制为 32 层间接引导。FIDL 编码器、解码器或验证器必须 该限制通过在调用过程中跟踪当前递归深度来实施 消息验证。
递归深度的正式定义:
- FIDL 消息的内联对象定义为具有递归深度 0。
- 每次通过指针或信封遍历间接遍历时 用 1 递增递归深度。
如果任何时候,递归深度超过 32,就必须 终止并引发错误。
例如:
type InlineObject = struct {
content_a string;
vector vector<OutOfLineStructAtLevel1>;
table TableInlineAtLevel0;
};
type OutOfLineStructAtLevel1 = struct {
content_b string;
};
type TableInlineAtLevel0 = table {
1: content_c string;
};
对 InlineObject
的实例进行编码时,我们有相应的递归深度:
content_a
的字节位于递归深度为 1 的位置,即content_a
字符串标头内嵌在InlineObject
结构体中,字节位于 可通过指针间接访问的外行对象。content_b
的字节位于递归深度为 2 的位置,即vector
标头内嵌在InlineObject
结构体中, 因此,OutOfLineStructAtLevel1
结构体的递归深度为 1,content_b
字符串标头内嵌在OutOfLineStructAtLevel1
中,并且 个字节位于可通过指针间接访问的外行对象中 从第 1 层开始,使深度为 2。content_c
的字节位于递归深度为 3 的位置,即table
标头内嵌在InlineObject
结构体中,表信封位于 深度为 1,指向深度为 2 的content_c
字符串标头,以及 字节位于可通过指针间接访问的外行对象中, 深入到 3 层。
验证
验证消息的目的是尽早发现传输格式错误 也有可能诱发安全或稳定性问题。
解码从对等端收到的消息时必须进行消息验证 以防止不良数据传播到服务入口点以外。
将消息编码为可选时,建议进行消息验证 以帮助对违反的完整性约束进行本地化。
为了尽可能减少运行时开销,验证通常应作为 一个密码,以便只发送 遍历。由于消息采用深度优先遍历顺序进行编码, 遍历展现出良好的内存局部性,因此应该非常高效。
对于简单的消息,验证可能非常简单,最多只需 很少检查尺寸虽然我们鼓励程序员依靠他们的 FIDL 绑定 代表他们验证消息的库,也可以进行验证 (如果需要的话)。
一致的 FIDL 绑定必须检查以下所有完整性约束:
- 消息的总大小,包括消息的所有外行子对象 等于包含该数据的缓冲区的总大小。全部 子对象。
- 消息引用的句柄总数正好等于 句柄表的总大小。会考虑所有标识名。
- 不超过复杂对象的最大递归深度。
- 所有枚举值都在其定义的范围内。
- 所有联合标记值都在其定义的范围内。
- 仅编码:
<ph type="x-smartling-placeholder">
- </ph>
- 遍历期间遇到的所有子对象的指针都精确引用 到子对象预计出现的下一个缓冲区位置。如 由此推论,指针绝不会引用缓冲区以外的位置。
- 仅解码:
<ph type="x-smartling-placeholder">
- </ph>
- 所引用子对象的所有存在和不存在标志都会存储 值只能为 0 或 UINTPTR_MAX。
- 所引用句柄的所有存在和不存在标记都会存储值 仅支持 0 或 UINT32_MAX。
标头标记
Flags[0]
位 | 当前用量 | 以往的用法 |
---|---|---|
7(MSB) | 未使用 | |
6 | 未使用 | |
5 | 未使用 | |
4 | 未使用 | |
3 | 未使用 | |
2 | 未使用 | |
1 | 指示是否使用 v2 传输格式 (RFC-0114) | |
0 | 未使用 | 指示静态联合体是否应编码为 xunions (RFC-0061) |
Flags[1]
位 | 当前用量 | 以往的用法 |
---|---|---|
7(MSB) | 未使用 | |
6 | 未使用 | |
5 | 未使用 | |
4 | 未使用 | |
3 | 未使用 | |
2 | 未使用 | |
1 | 未使用 | |
0 | 未使用 |
Flags[2]
位 | 当前用量 | 以往的用法 |
---|---|---|
7(MSB) | 未使用 | |
6 | 未使用 | |
5 | 未使用 | |
4 | 未使用 | |
3 | 未使用 | |
2 | 未使用 | |
1 | 未使用 | |
0 | 未使用 |
-
定义零句柄以表示“没有句柄”这意味着您可以安全地 将 Wi-Fi 格式结构默认初始化为零。零也是
ZX_HANDLE_INVALID
常量的值。↩ -
深入了解《The Lost Art of Structure Packing》 相关论文。↩