• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# TEE 安全驱动开发指导<a name="ZH-CN_TOPIC_0000001212014566"></a>
2
3## 概述<a name="section351681313544"></a>
4
5### 功能简介<a name="section167701178548"></a>
6
7本文对TEE安全驱动的开发流程、接口、函数库等进行说明,指导驱动开发者进行安全驱动程序的开发与调试工作。
8
9### 约束与限制<a name="section67447370556"></a>
10
11-   开发的驱动程序仅支持在TEE可信执行环境子系统上加载和运行。
12
13### 场景介绍<a name="section148731215195617"></a>
14
15目前TEEOS支持内置驱动的开发,驱动和TEEOS镜像共同编译打包。具体开发指导请参考开发示例章节。
16
17## 驱动开发框架<a name="section12432132218372"></a>
18
19驱动开发整体可以分为两部分,第一个是驱动业务开发框架,第二个是访问该驱动的驱动访问者框架。
20
21### 驱动业务框架<a name="section6705194712373"></a>
22
23为方便各个驱动开发统一,TEE可信执行环境子系统为各个驱动设计了一套基础框架,如下所示,驱动开发者结合驱动实际逻辑分别定义这些基础函数即可。
24```
25#define DRV_NAME_MAX_LEN 32U
26#define DRV_RESERVED_NUM 8U
27
28struct drv_data {
29    int32_t fd; /* fd信息,对应驱动的唯一标识 */
30    uint32_t taskid; /* 访问者的taskid */
31    void *private_data; /* 私有数据 */
32    struct tee_uuid uuid; /* 访问者的uuid */
33};
34
35/* 驱动加载时初始化函数 */
36typedef int32_t (*init_func)(void);
37
38/* 驱动在系统休眠时被调用的函数 */
39typedef int32_t (*suspned_func)(void);
40
41/* 驱动在系统唤醒时被调用的函数 */
42typedef int32_t (*resume_func)(void);
43
44/* 驱动被访问时命令分发函数 */
45typedef int64_t (*ioctl_func)(struct drv_data *drv, uint32_t cmd, unsigned long args, uint32_t args_len);
46
47/* 驱动被访问时初始化函数 */
48typedef int64_t (*open_func)(struct drv_data *drv, unsigned long args, uint32_t args_len);
49
50/* 驱动被访问结束时资源释放函数 */
51typedef int64_t (*close_func)(struct drv_data *drv);
52
53struct tee_driver_module {
54    init_func init;
55    ioctl_func ioctl;
56    open_func open;
57    close_func close;
58    suspned_func suspend;
59    resume_func resume;
60    suspned_func suspend_s4;
61    resume_func resume_s4;
62    uint64_t reserved[DRV_RESERVED_NUM]; /* has not used, just reserved */
63};
64
65#define tee_driver_declare(name, init, open, ioctl, close, suspend, resume, suspend_s4, resume_s4) \
66__attribute__((visibility("default"))) const struct tee_driver_module g_driver_##name = { \
67    init, ioctl, open, close, suspend, resume, suspend_s4, resume_s4, {0} }
68```
69
70结构体struct tee_driver_module便是每个驱动业务开发时需要注册的信息,各个变量说明如下:
71
72**表 1** 驱动业务开发注册信息表
73
74<a></a>
75<table><thead align="left"><tr><th class="cellrowborder" valign="top" width="33.33333333333333%"><p>变量名</p>
76</th>
77<th class="cellrowborder" valign="top" width="33.33333333333333%"><p>类型</p>
78</th>
79<th class="cellrowborder" valign="top" width="33.33333333333333%"><p>说明</p>
80</th>
81</tr>
82</thead>
83<tbody><tr><td><p>name</p></td>
84<td><p>常量字符串</p></td>
85<td><p>驱动名字,每个驱动必须唯一,有效长度小于32个字节,仅支持数字、字母和'_'。</p></td>
86</tr>
87<tr><td><p>init</p></td>
88<td><p>init_func函数指针</p></td>
89<td><p>驱动加载时初始化函数。</p></td>
90</tr>
91<tr><td><p>open</p></td>
92<td><p>函数指针</p></td>
93<td><p>驱动被访问时初始化函数。</p></td>
94</tr>
95<tr><td><p>ioctl</p></td>
96<td><p>函数指针</p></td>
97<td><p>驱动被访问时命令分发函数。</p></td>
98</tr>
99<tr><td><p>close</p></td>
100<td><p>函数指针</p></td>
101<td><p>驱动被访问结束时资源释放函数。</p></td>
102</tr>
103<tr><td><p>suspend</p></td>
104<td><p>函数指针</p></td>
105<td><p>驱动在系统休眠时被调用的函数。</p></td>
106</tr>
107<tr><td><p>resume</p></td>
108<td><p>函数指针</p></td>
109<td><p>驱动在系统唤醒时被调用的函数。</p></td>
110</tr>
111<tr><td><p>suspend_s4</p></td>
112<td><p>函数指针</p></td>
113<td><p>驱动在系统休眠时被调用的函数,对应linux kernel里freeze_noirq操作流程。</p></td>
114</tr>
115<tr><td><p>resume_s4</p></td>
116<td><p>函数指针</p></td>
117<td><p>驱动在系统唤醒时被调用的函数,对应linux kernel里restore_noirq操作流程。</p></td>
118</tr>
119<tr><td><p>reserved</p></td>
120<td><p>预留</p></td>
121<td><p>现有框架暂未使用。</p></td>
122</tr>
123</tbody>
124</table>
125
126**表 2** 驱动业务框架接口说明
127<a></a>
128<table><thead><tr><th class="cellrowborder" valign="top" width="50%"><p>接口名</p>
129</th>
130<th class="cellrowborder" valign="top" width="50%"><p>描述</p>
131</th>
132</tr>
133</thead>
134<tbody><tr><td><p>int32_t (*init_func)(void)</p></td>
135<td><p>该函数是在驱动加载完后便被驱动框架调用的初始化函数,其主要作用是在该驱动被访问之前进行初始化操作。该函数在驱动加载后的整个生命周期内只会被调用一次。</p>
136<p><b>返回值:</b></p>
137<p>0:初始化成功</p>
138<p>非0:初始化失败</p></td>
139</tr>
140<tr><td><p>int64_t (*open_func)(struct drv_data *drv, unsigned long args, uint32_t args_len)</p></td>
141<td><p>该函数是驱动访问者访问驱动时调用的初始化函数,其主要作用是在驱动里申请一个fd,并进行初始化。该函数在每次新增驱动访问时都会调用。</p>
142<p><b>参数:</b></p>
143<p>drv:入参,表示此次open该驱动的fd所有信息</p>
144<p>args:入参,表示给驱动传入参数对应的buffer地址,由驱动访问者设置</p>
145<p>args_len:入参,表示给驱动传入参数对应的buffer长度,由驱动访问者设置</p>
146<p><b>返回值:</b></p>
147<p>非正数:异常值</p>
148<p>其他:返回的fd信息</p></td>
149</tr>
150<tr><td><p>int64_t (*ioctl_func)(struct drv_data *drv, uint32_t cmd, unsigned long args, uint32_t args_len)</p></td>
151<td><p>该函数是驱动在open初始化之后,进行的一系列针对业务逻辑的操作。其主要作用是根据传入的drv获取fd资源信息,再执行cmd命令对应的执行流,其中[args.args_len]组成的buffer信息是给该cmd执行流传入的参数。</p>
152<p><b>参数:</b></p>
153<p>drv:入参,表示此次ioctl该驱动的fd所有信息,fd由驱动访问者传入,驱动框架根据fd传入对应drv_data结构体</p>
154<p>cmd:入参,表示此次ioctl该驱动传入的命令号,驱动可根据不同命令号执行不同的业务逻辑,由驱动访问者设置</p>
155<p>args:入参,表示给驱动传递参数的buffer基地址</p>
156<p>args_len:入参,表示给驱动传递参数的buffer长度</p>
157<p><b>返回值:</b></p>
158<p>0:操作成功</p>
159<p>-1:操作失败,框架层面返回的异常值</p>
160<p>其他值:操作失败,驱动自行定义的异常值</p></td>
161</tr>
162<tr><td><p>int64_t (*close_func)(struct drv_data *drv)</p></td>
163<td><p>该函数主要作用是在驱动业务逻辑访问结束后进行对该fd对应的资源清理操作。</p>
164<p><b>参数:</b></p>
165<p>drv:入参,表示此次ioctl该驱动的fd所有信息</p>
166<p><b>返回值:</b></p>
167<p>0:操作成功</p>
168<p>非0:操作失败</p></td>
169</tr>
170<tr><td><p>int32_t (*suspned_func)(void)</p></td>
171<td><p>该函数主要作用是此驱动休眠状态下的一些列操作,会在系统休眠时有驱动框架自行调用。</p>
172<p><b>返回值:</b></p>
173<p>0:操作成功</p>
174<p>非0:操作失败</p></td>
175</tr>
176<tr><td><p>int32_t (*resume_func)(void)</p></td>
177<td><p>该函数主要作用是此驱动唤醒态下的一系列操作,会在系统唤醒流程中由驱动框架自行调用,与suspend函数对应。</p>
178<p><b>返回值:</b></p>
179<p>0:操作成功</p>
180<p>非0:操作失败</p></td>
181</tr>
182</tbody>
183</table>
184
185### 驱动访问者框架<a name="section18123151133811"></a>
186
187驱动访问时,驱动访问者先调用tee_drv_open函数获取驱动唯一标记fd;再调用tee_drv_ioctl函数,传入cmd信息,访问该驱动对应cmd执行流,如果针对某个fd有多个ioctl执行流,多次调用tee_drv_ioctl即可;如果访问结束,驱动访问者还需要调用tee_drv_close函数关闭该fd信息。
188
189**表 3** 驱动访问者框架接口说明
190
191<a></a>
192<table><thead><tr><th class="cellrowborder" valign="top" width="50%"><p>接口名</p>
193</th>
194<th class="cellrowborder" valign="top" width="50%"><p>描述</p>
195</th>
196</tr>
197</thead>
198<tbody><tr><td><p>int64_t tee_drv_open(const char *drv_name, const void *param, uint32_t param_len)</p></td>
199<td><p>主要作用是驱动访问者通过调用该函数,访问drv_name指定的驱动,调用驱动的open函数,返回与该驱动对应的唯一标记fd信息。其中param buffer对应的内容组装结构由drv_name对应驱动定义,实际与驱动open函数里[args.args_len]表示的buffer内容一致。</p>
200<p><b>参数:</b></p>
201<p>drv_name:入参,表示要访问的驱动名称;</p>
202<p>param:入参,表示给驱动传递的参数地址;</p>
203<p>param_len:入参,表示给驱动传递的参数长度,与param组成的buffer内容便是给驱动传递的参数信息。</p>
204<p><b>返回值:</b></p>
205<p>非正数:非法值,操作失败</p>
206<p>大于0:fd信息,对应驱动的唯一标识</p></td>
207</tr>
208<tr><td><p>int64_t tee_drv_ioctl(int64_t fd, uint32_t cmd_id, const void *param, uint32_t param_len)</p></td>
209<td><p>主要作用是驱动访问者通过调用该函数,访问fd对应的驱动模块,执行命令ID号为cmd_id对应的业务逻辑,传入参数为param与param_len对应buffer存储的内容,其中param与param_len对应buffer内容组装结构由fd对应的驱动定义,实际与驱动ioctl函数[args.args_len]组成的buffer内容一致。</p>
210<p><b>参数:</b></p>
211<p>fd:入参,表示open该驱动成功返回时的返回值;</p>
212<p>cmd_id:入参,表示ioctl该驱动时对应的命令id号;</p>
213<p>param:入参,表示ioctl该驱动cmd_id流程时传入的参数基地址;</p>
214<p>param_len:入参,表示ioctl该驱动cmd_id流程时传入的参数buffer长度。与param组成的buffer内容便是给驱动命令号cmd_id对应的参数信息。</p>
215<p><b>返回值:</b></p>
216<p>0:操作成功</p>
217<p>-1:框架层面访问失败</p>
218<p>其他值:各驱动自定义失败返回值</p></td>
219</tr>
220<tr><td><p>int64_t tee_drv_close(int64_t fd)</p></td>
221<td><p>主要作用是关闭fd对应驱动信息,一般常见操作是释放该fd维护的驱动资源。</p>
222<p><b>返回值:</b></p>
223<p>0:操作成功</p>
224<p>-1:操作失败</p></td>
225</tr>
226</tbody>
227</table>
228
229## 接口说明<a name="section1748173625619"></a>
230
231### 地址转换接口说明<a name="section101297155716"></a>
232
233驱动进行地址转换操作需要使用的接口列表。
234
235**表 4**  地址转换接口列表
236
237<a name="table13739184111427"></a>
238<table><thead align="left"><tr id="row2739154118421"><th class="cellrowborder" valign="top" width="54.31%" id="mcps1.2.3.1.1"><p id="p462103214410"><a name="p462103214410"></a><a name="p462103214410"></a>接口名</p>
239</th>
240<th class="cellrowborder" valign="top" width="45.69%" id="mcps1.2.3.1.2"><p id="p1762163219448"><a name="p1762163219448"></a><a name="p1762163219448"></a>描述</p>
241</th>
242</tr>
243</thead>
244<tbody><tr id="row7739441104213"><td class="cellrowborder" valign="top" width="54.31%" headers="mcps1.2.3.1.1 "><p id="p137395418427"><a name="p137395418427"></a><a name="p137395418427"></a>uint64_t drv_virt_to_phys(uintptr_t addr);</p>
245</td>
246<td class="cellrowborder" valign="top" width="45.69%" headers="mcps1.2.3.1.2 "><p id="p177391841124218"><a name="p177391841124218"></a><a name="p177391841124218"></a>虚拟地址转换为物理地址。</p>
247</td>
248</tr>
249</tbody>
250</table>
251
252### map接口说明<a name="section1831091675716"></a>
253
254驱动进行内存映射操作所需要的接口列表。
255
256**表 5**  map接口列表
257
258<a name="table1690431511432"></a>
259<table><thead align="left"><tr id="row189041315194317"><th class="cellrowborder" valign="top" width="54.67999999999999%" id="mcps1.2.3.1.1"><p id="p34281633124413"><a name="p34281633124413"></a><a name="p34281633124413"></a>接口名</p>
260</th>
261<th class="cellrowborder" valign="top" width="45.32%" id="mcps1.2.3.1.2"><p id="p4428133174412"><a name="p4428133174412"></a><a name="p4428133174412"></a>描述</p>
262</th>
263</tr>
264</thead>
265<tbody><tr id="row9904121594312"><td class="cellrowborder" valign="top" width="54.67999999999999%" headers="mcps1.2.3.1.1 "><p id="p1090471594316"><a name="p1090471594316"></a><a name="p1090471594316"></a>int32_t tee_map_secure(paddr_t paddr, uint64_t size, uintptr_t *vaddr, cache_mode_type cache_mode);</p>
266</td>
267<td class="cellrowborder" valign="top" width="45.32%" headers="mcps1.2.3.1.2 "><p id="p583mcpsimp"><a name="p583mcpsimp"></a><a name="p583mcpsimp"></a>给驱动访问者映射一段安全属性的物理内存。</p>
268</td>
269</tr>
270<tr id="row190417158431"><td class="cellrowborder" valign="top" width="54.67999999999999%" headers="mcps1.2.3.1.1 "><p id="p4904715174317"><a name="p4904715174317"></a><a name="p4904715174317"></a>int32_t tee_map_nonsecure(paddr_t paddr, uint64_t size, uintptr_t *vaddr, cache_mode_type cache_mode);</p>
271</td>
272<td class="cellrowborder" valign="top" width="45.32%" headers="mcps1.2.3.1.2 "><p id="p10904115204310"><a name="p10904115204310"></a><a name="p10904115204310"></a>给驱动访问者映射一段非安全属性的物理内存,其中映射属性是只读不能写。</p>
273</td>
274</tr>
275</tbody>
276</table>
277
278### IO操作接口说明<a name="section6512133012574"></a>
279
280驱动进行IO操作所需要的接口列表。
281
282**表 6**  IO操作接口列表
283
284<a name="table6311346194315"></a>
285<table><thead align="left"><tr id="row831212462439"><th class="cellrowborder" valign="top" width="54.730000000000004%" id="mcps1.2.3.1.1"><p id="p7945143412442"><a name="p7945143412442"></a><a name="p7945143412442"></a>接口名</p>
286</th>
287<th class="cellrowborder" valign="top" width="45.269999999999996%" id="mcps1.2.3.1.2"><p id="p7945183494416"><a name="p7945183494416"></a><a name="p7945183494416"></a>描述</p>
288</th>
289</tr>
290</thead>
291<tbody><tr id="row143121846164318"><td class="cellrowborder" valign="top" width="54.730000000000004%" headers="mcps1.2.3.1.1 "><p id="p133121246194317"><a name="p133121246194317"></a><a name="p133121246194317"></a>void *ioremap(uintptr_t phys_addr, unsigned long size, int32_t prot);</p>
292</td>
293<td class="cellrowborder" valign="top" width="45.269999999999996%" headers="mcps1.2.3.1.2 "><p id="p133126466437"><a name="p133126466437"></a><a name="p133126466437"></a>将IO地址映射至虚拟地址。</p>
294</td>
295</tr>
296<tr id="row1431214468430"><td class="cellrowborder" valign="top" width="54.730000000000004%" headers="mcps1.2.3.1.1 "><p id="p103122046114317"><a name="p103122046114317"></a><a name="p103122046114317"></a>int32_t iounmap(uintptr_t pddr, void *addr);</p>
297</td>
298<td class="cellrowborder" valign="top" width="45.269999999999996%" headers="mcps1.2.3.1.2 "><p id="p4312194674313"><a name="p4312194674313"></a><a name="p4312194674313"></a>解除物理地址映射。</p>
299</td>
300</tr>
301<tr id="row1131211467433"><td class="cellrowborder" valign="top" width="54.730000000000004%" headers="mcps1.2.3.1.1 "><p id="p63121446154315"><a name="p63121446154315"></a><a name="p63121446154315"></a>void read_from_io (void *to, const volatile void *from, unsigned long count);</p>
302</td>
303<td class="cellrowborder" valign="top" width="45.269999999999996%" headers="mcps1.2.3.1.2 "><p id="p16312174619438"><a name="p16312174619438"></a><a name="p16312174619438"></a>将IO输入的值读取至驱动指定的地址,读取长度由count指定。</p>
304</td>
305</tr>
306<tr id="row1331219468434"><td class="cellrowborder" valign="top" width="54.730000000000004%" headers="mcps1.2.3.1.1 "><p id="p8312104614437"><a name="p8312104614437"></a><a name="p8312104614437"></a>void write_to_io(volatile void *to, const void *from, unsigned long count);</p>
307</td>
308<td class="cellrowborder" valign="top" width="45.269999999999996%" headers="mcps1.2.3.1.2 "><p id="p193mcpsimp"><a name="p193mcpsimp"></a><a name="p193mcpsimp"></a>将驱动指定地址的值输出至IO,读取长度由count指定。</p>
309</td>
310</tr>
311</tbody>
312</table>
313
314### 内存拷贝接口说明<a name="section75381736318"></a>
315
316驱动进行内存拷贝操作所需要的接口列表。
317
318**表 7**  内存拷贝接口列表
319
320<a name="table7469133214314"></a>
321<table><thead align="left"><tr id="row24693321135"><th class="cellrowborder" valign="top" width="55.35%" id="mcps1.2.3.1.1"><p id="p109015511039"><a name="p109015511039"></a><a name="p109015511039"></a>接口名</p>
322</th>
323<th class="cellrowborder" valign="top" width="44.65%" id="mcps1.2.3.1.2"><p id="p2090117510315"><a name="p2090117510315"></a><a name="p2090117510315"></a>描述</p>
324</th>
325</tr>
326</thead>
327<tbody><tr id="row15469133212312"><td class="cellrowborder" valign="top" width="55.35%" headers="mcps1.2.3.1.1 "><p id="p04692032734"><a name="p04692032734"></a><a name="p04692032734"></a>int32_t copy_from_client(uint64_t src, uint32_t src_size, uintptr_t dst, uint32_t dst_size);</p>
328</td>
329<td class="cellrowborder" valign="top" width="44.65%" headers="mcps1.2.3.1.2 "><p id="p184693323311"><a name="p184693323311"></a><a name="p184693323311"></a>将驱动内存拷入client端。</p>
330</td>
331</tr>
332<tr id="row246915325319"><td class="cellrowborder" valign="top" width="55.35%" headers="mcps1.2.3.1.1 "><p id="p94881980512"><a name="p94881980512"></a><a name="p94881980512"></a>int32_t copy_to_client(uintptr_t src, uint32_t src_size, uint64_t dst, uint32_t dst_size);</p>
333</td>
334<td class="cellrowborder" valign="top" width="44.65%" headers="mcps1.2.3.1.2 "><p id="p647018327314"><a name="p647018327314"></a><a name="p647018327314"></a>将client端数据拷出至驱动。</p>
335</td>
336</tr>
337</tbody>
338</table>
339
340### 共享内存接口说明<a name="section5891654459"></a>
341
342驱动进行共享内存操作所需要的接口列表。
343
344**表 8**  共享内存接口列表
345
346<a name="table186909151063"></a>
347<table><thead align="left"><tr id="row369016151263"><th class="cellrowborder" valign="top" width="55.620000000000005%" id="mcps1.2.3.1.1"><p id="p1033416207618"><a name="p1033416207618"></a><a name="p1033416207618"></a>接口名</p>
348</th>
349<th class="cellrowborder" valign="top" width="44.379999999999995%" id="mcps1.2.3.1.2"><p id="p19334172010619"><a name="p19334172010619"></a><a name="p19334172010619"></a>描述</p>
350</th>
351</tr>
352</thead>
353<tbody><tr id="row1069019153610"><td class="cellrowborder" valign="top" width="55.620000000000005%" headers="mcps1.2.3.1.1 "><p id="p176901815266"><a name="p176901815266"></a><a name="p176901815266"></a>void *tee_alloc_sharemem_aux(const struct tee_uuid *uuid, uint32_t size);</p>
354</td>
355<td class="cellrowborder" valign="top" width="44.379999999999995%" headers="mcps1.2.3.1.2 "><p id="p11690101520612"><a name="p11690101520612"></a><a name="p11690101520612"></a>申请进程间通信共享内存。</p>
356</td>
357</tr>
358<tr id="row19690615967"><td class="cellrowborder" valign="top" width="55.620000000000005%" headers="mcps1.2.3.1.1 "><p id="p166901915464"><a name="p166901915464"></a><a name="p166901915464"></a>uint32_t tee_free_sharemem(void *addr, uint32_t size);</p>
359</td>
360<td class="cellrowborder" valign="top" width="44.379999999999995%" headers="mcps1.2.3.1.2 "><p id="p186901215366"><a name="p186901215366"></a><a name="p186901215366"></a>释放进程间通信共享内存。</p>
361</td>
362</tr>
363</tbody>
364</table>
365
366## 开发示例<a name="section198361520981"></a>
367### 编译文件配置
368- 进入base/tee/tee_os_framework/目录
369- 首先在drivers/目录新建一个目录,例如demo_driver
370- 在demo_driver目录新建src目录用于存放源代码文件,新建Makefile编译文件
371
372Makefile示例如下
373
374```
375DRIVER := demo_driver.elf
376
377include $(BUILD_CONFIG)/var.mk
378
379demo_driver_c_files += $(wildcard src/*.c)
380
381#include
382inc-flags += -I./src
383
384# Libraries
385
386SVC_PARTITIAL_LINK = y
387include $(BUILD_SERVICE)/svc-common.mk
388```
389
390- 修改build/mk/common/operation/project.mk,增加drivers += demo_driver
391- 修改build/mk/pack/plat_config.mk, 增加以下内容
392
393```
394ifeq ($(CONFIG_ARCH_AARCH64),y)
395product_apps += $(OUTPUTDIR)/aarch64/drivers/demo_driver.elf
396check-a64-syms-y += $(OUTPUTDIR)/aarch64/drivers/demo_driver.elf
397else
398product_apps += $(OUTPUTDIR)/arm/drivers/demo_driver.elf
399check-syms-y += $(OUTPUTDIR)/arm/drivers/demo_driver.elf
400endif
401```
402
403### 驱动开发示例<a name="section198361520981"></a>
404
405驱动框架注册实例如下:
406
407```
408#define TEST_NUM_INIT_VAL 0x11
409#define TEST_NUM_ADD_TAG 0x10
410static int32_t g_test_num = TEST_NUM_INIT_VAL;
411
412/* 驱动初始化函数 */
413int32_t init_test(void)
414{
415    if (g_test_num != TEST_NUM_INIT_VAL) {
416        tloge("driver init test failed, g_test_num:0x%x not equal 0x%x\n", g_test_num, TEST_NUM_INIT_VAL);
417        return -1;
418    }
419
420    g_test_num += TEST_NUM_ADD_TAG;
421    tloge("driver init test end\n");
422    return 0;
423}
424
425/* buffer校验的相关逻辑 */
426static int32_t buf_check(uint32_t *buf, uint32_t size, uint32_t args)
427{
428    if (buf == NULL) {
429        tloge("buf is invalid, check failed\n");
430        return -1;
431    }
432
433    uint32_t i;
434    for (i = 0; i < size; i++) {
435        if (buf[i] != args) {
436            tloge("buf[%u]=%u which not equal %u\n", i, buf[i], args);
437            return -1;
438        }
439    }
440
441    return 0;
442}
443
444/* 驱动具体业务处理逻辑函数 */
445static int64_t args_test(struct drv_data *drv, unsigned long args, uint32_t args_len)
446{
447    /* cmd处理函数在使用参数之前需要判断参数合法性 */
448    if (args_len != sizeof(uint32_t) || args == 0) {
449        tloge("invalid args args_len:%u\n", args_len);
450        return -1;
451    }
452
453    uint32_t *input_args = (uint32_t *)(uintptr_t)args;
454
455    tloge("driver args test begin: drv.fd=%d args=0x%x g_test_num:0x%x\n", drv->fd, *input_args, g_test_num);
456    int64_t ret = buf_check(drv->private_data, TOKEN_BUF_SIZE, *input_args);
457    if (ret != 0)
458        tloge("args test FAIL\n");
459    else
460        tloge("args test SUCC\n");
461
462    return ret;
463}
464
465/* 驱动命令分发函数,根据不同cmdid调用不同函数逻辑 */
466int64_t ioctl_test(struct drv_data *drv, uint32_t cmd, unsigned long args, uint32_t args_len)
467{
468    if (drv == NULL) { /* drv可以在调用业务逻辑之前判断,args和args_len需要根据具体cmdid逻辑去判断 */
469        tloge("ioctl invalid drv\n");
470        return -1;
471    }
472
473    int64_t ret = -1;
474
475    switch (cmd) {
476    case ARGS_TEST_ID:
477        ret = args_test(drv, args, args_len);
478        break;
479    default:
480        tloge("cmd:0x%x not support\n", cmd);
481    }
482
483    return ret;
484}
485
486/* buffer 初始化 */
487static uint32_t *buf_init(uint32_t args)
488{
489    uint32_t *buf = (uint32_t *)malloc(TOKEN_BUF_SIZE * sizeof(uint32_t));
490    if (buf == NULL) {
491        tloge("alloc buf failed\n");
492        return NULL;
493    }
494
495    int32_t i;
496    for (i = 0; i < TOKEN_BUF_SIZE; i++)
497        buf[i] = args;
498
499    return buf;
500}
501
502/* 驱动被访问时初始化函数 */
503int64_t open_test(struct drv_data *drv, unsigned long args, uint32_t args_len)
504{
505    if (drv == NULL) {
506        tloge("open invalid drv\n");
507        return -1;
508    }
509
510    if (args_len < sizeof(uint32_t) || args == 0) {
511        tloge("open invalid drv\n");
512        return -1;
513    }
514
515    uint32_t *input = (uint32_t *)args;
516    if (*input == UINT32_MAX) {
517        tloge("open test input args is UINT32_MAX, just retrun -1\n");
518        return -1;
519    }
520
521    uint32_t *buf = buf_init(*input);
522    if (buf == NULL)
523        return -1;
524
525    /* 将buf赋值给fd结构的private_data,后续都可以通过此fd获取到buf内容 */
526    drv->private_data = buf;
527    tloge("driver open test begin: fd=%d args=0x%x g_test_num:0x%x\n", drv->fd, *input, g_test_num);
528
529    return 0;
530}
531
532/* 驱动业务逻辑访问结束后的资源清理操作 */
533int64_t close_test(struct drv_data *drv)
534{
535    if (drv == NULL) {
536        tloge("close invalid drv\n");
537        return -1;
538    }
539
540    tloge("driver close test begin: fd:%d g_test_num:0x%x\n", drv->fd, g_test_num);
541    /* close流程需要释放fd对应的所有资源 */
542    if (drv->private_data != NULL) {
543        tloge("free private data in close\n");
544        free(drv->private_data);
545    }
546
547    return 0;
548}
549
550/* 在系统休眠时由驱动框架自行调用 */
551int32_t suspend_test(void)
552{
553    tloge("suspend test begin\n");
554    return 0;
555}
556
557/* 在系统唤醒时有驱动框架自行调用 */
558int32_t resume_test(void)
559{
560    tloge("resume test begin\n");
561    return 0;
562}
563
564/* 在系统s4休眠时被调用的函数 */
565int32_t suspend_s4_test(void)
566{
567    tloge("suspend_s4 test begin\n");
568    return 0;
569}
570
571/* 在系统s4唤醒时被调用的函数 */
572int32_t resume_s4_test(void)
573{
574    tloge("resume_s4 test begin\n");
575    return 0;
576}
577
578/* 驱动框架注册 */
579tee_driver_declare(drv_test_module, init_test, open_test, ioctl_test, close_test, \
580                   suspend_test, resume_test, suspend_s4_test, resume_s4_test);
581```
582
583### 驱动访问者开发示例<a name="section198361520981"></a>
584```
585
586#include <securec.h>
587#include <stdlib.h>
588#include <string.h>
589#include <tee_drv_client.h>
590#include <tee_ext_api.h>
591#include <tee_log.h>
592#include <test_drv_cmdid.h>
593#include <mem_ops.h>
594
595
596#define DRV_UUID1                                          \
597    {                                                      \
598        0x11112222, 0x0000, 0x0000,                        \
599        {                                                  \
600            0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11 \
601        }                                                  \
602    }
603
604#define BUFFER_SIZE 1024
605struct share_buffer_arg {
606    uint64_t addr;
607    uint32_t len;
608    uint32_t share_token;
609};
610
611/* 访问驱动的各个流程,在TA的TA_InvokeCommandEntryPoint阶段被执行 */
612static TEE_Result TeeTestDrive(uint32_t cmd)
613{
614    int ret;
615    const char *drvName = "drv_test_module";
616    uint32_t args = (uint32_t)(&drvName);
617    const char drvcallerInput[] = "the param is drvcaller_input";
618    char drvOutput[] = "DRVMEM_OUTPUT";
619
620    uint32_t drvcallerInputLen = (uint32_t)strlen(drvcallerInput) + 1;
621    uint32_t drvOutputLen = (uint32_t)strlen(drvOutput) + 1;
622    TEE_UUID uuid = DRV_UUID1;
623
624    /* 调用驱动的open函数,返回与该驱动对应的唯一标记fd信息 */
625    int64_t fd = tee_drv_open(drvName, &args, sizeof(args));
626    if (fd <= 0) {
627        tloge("open %s for get fd failed\n", drvName);
628        return TEE_ERROR_GENERIC;
629    }
630
631    char *tempBuffer = tee_alloc_sharemem_aux(&uuid, BUFFER_SIZE);
632    if (tempBuffer == NULL) {
633        tloge("alloc share mem failed\n");
634        return TEE_ERROR_GENERIC;
635    }
636    (void)memset_s(tempBuffer, BUFFER_SIZE, 0x0, BUFFER_SIZE);
637    ret = strcpy_s(tempBuffer, drvcallerInputLen, drvcallerInput);
638    if (ret != 0) {
639        tloge("strcpy_s failed,ret = 0x%x\n", ret);
640        return TEE_ERROR_GENERIC;
641    }
642
643    struct share_buffer_arg inputArg = { 0 };
644#ifndef __aarch64__
645    inputArg.addr = (uint64_t)(uint32_t)tempBuffer;
646#else
647    inputArg.addr = (uint64_t)tempBuffer;
648#endif
649
650    inputArg.len = BUFFER_SIZE;
651
652    tlogi("%s drv test ioctl begin args:0x%x fd:%d\n", drvName, inputArg, (int32_t)fd);
653
654    /* 访问fd对应的驱动模块,执行命令ID号为cmd_id对应的业务逻辑 */
655    ret = (int)tee_drv_ioctl(fd, cmd, (const void *)(&inputArg), sizeof(inputArg));
656    if (ret != 0) {
657        tloge("%s drv test ioctl failed, fd:%d \n", drvName, (int32_t)fd);
658    }
659    if (cmd == DRVTEST_COMMAND_COPYTOCLIENT) {
660        if (strncmp(drvOutput, (char *)tempBuffer, drvOutputLen) != 0) {
661            tloge("%s drv copy_to_client test failed, fd:%d, heap_buffer is:%s \n", drvName, (int32_t)fd, tempBuffer);
662            free_sharemem(tempBuffer, BUFFER_SIZE);
663            return TEE_ERROR_GENERIC;
664        }
665    }
666
667    /* 关闭fd对应驱动信息 */
668    ret |= (int)tee_drv_close(fd);
669    if (ret != 0) {
670        tloge("drv test fail!\n");
671    }
672
673    if (free_sharemem(tempBuffer, BUFFER_SIZE) != 0) {
674        tloge("free sharemem failed\n");
675        ret = -1;
676    }
677    return (TEE_Result)ret;
678}
679
680/* TA实例的构造函数,每个TA实例的生命周期中只被调用一次 */
681TEE_Result TA_CreateEntryPoint(void)
682{
683    tlogi("---- TA_CreateEntryPoint ----------- \n");
684
685    return TEE_SUCCESS;
686}
687
688/* 在CA请求创建一个与TA的会话时,TEE系统会调用此函数 */
689TEE_Result TA_OpenSessionEntryPoint(uint32_t parmType, TEE_Param params[4], void **sessionContext)
690{
691    (void)parmType;
692    (void)sessionContext;
693    tlogi("---- TA_OpenSessionEntryPoint -------- \n");
694    if (params[0].value.b == 0xFFFFFFFE)
695        return TEE_ERROR_GENERIC;
696    else
697        return TEE_SUCCESS;
698}
699
700/* 在CA发送指令给TA时,需要指定之前创建成功的会话,TEE系统收到请求后会调用此函数 */
701TEE_Result TA_InvokeCommandEntryPoint(void *sessionContext, uint32_t cmd, uint32_t parmType, TEE_Param params[4])
702{
703    TEE_Result ret = TEE_SUCCESS;
704    (void)sessionContext;
705    (void)parmType;
706    (void)params;
707    tlogi("---- TA invoke command ----------- command id: %u\n", cmd);
708
709    switch (cmd) {
710        case DRVTEST_COMMAND_DRVVIRTTOPHYS:
711        case DRVTEST_COMMAND_COPYFROMCLIENT:
712        case DRVTEST_COMMAND_COPYTOCLIENT:
713            ret = TeeTestDrive(cmd);
714            if (ret != TEE_SUCCESS)
715                tloge("invoke command for driver test failed! cmdId: %u, ret: 0x%x\n", cmd, ret);
716            break;
717        default:
718            tloge("not support this invoke command! cmdId: %u\n", cmd);
719            ret = TEE_ERROR_GENERIC;
720            break;
721    }
722
723    return ret;
724}
725
726/* 在CA发起关闭与TA的会话连接时,TEE系统会调用此函数 */
727void TA_CloseSessionEntryPoint(void *sessionContext)
728{
729    (void)sessionContext;
730    tlogi("---- TA_CloseSessionEntryPoint ----- \n");
731}
732
733/* TA实例的析构函数,TEE系统在销毁TA实例时调用此函数 */
734void TA_DestroyEntryPoint(void)
735{
736    tlogi("---- TA_DestroyEntryPoint ---- \n");
737}
738```
739
740## 标准C库支持<a name="section14109139161012"></a>
741
742支持绝大多数的libc接口。支持大多数的POSIX接口,具体支持情况请看附件。标准文档请参照如下网址:
743
744POSIX:[https://mirror.math.princeton.edu/pub/oldlinux/download/c953.pdf](https://mirror.math.princeton.edu/pub/oldlinux/download/c953.pdf)
745
746目前使用的openharmony的musl-1.2.5/libc库。
747
748**表 9**  标准C支持列表
749
750<a name="table7336617112614"></a>
751<table><thead align="left"><tr id="row1633681714266"><th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.2.4.1.1"><p id="p1653154512717"><a name="p1653154512717"></a><a name="p1653154512717"></a>模块</p>
752</th>
753<th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.2.4.1.2"><p id="p1253114512274"><a name="p1253114512274"></a><a name="p1253114512274"></a>函数接口名</p>
754</th>
755<th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.2.4.1.3"><p id="p75311145202718"><a name="p75311145202718"></a><a name="p75311145202718"></a>说明</p>
756</th>
757</tr>
758</thead>
759<tbody><tr id="row6340121710262"><td class="cellrowborder" rowspan="6" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p18534845102711"><a name="p18534845102711"></a><a name="p18534845102711"></a>malloc</p>
760</td>
761<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p553444592710"><a name="p553444592710"></a><a name="p553444592710"></a>aligned_alloc</p>
762</td>
763<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 ">-</td>
764</tr>
765<tr id="row10341181782614"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p753424552719"><a name="p753424552719"></a><a name="p753424552719"></a>calloc</p>
766</td>
767<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
768</tr>
769<tr id="row534110172268"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1853444542719"><a name="p1853444542719"></a><a name="p1853444542719"></a>malloc</p>
770</td>
771<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
772</tr>
773<tr id="row203411176269"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1553474572712"><a name="p1553474572712"></a><a name="p1553474572712"></a>realloc</p>
774</td>
775<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
776</tr>
777<tr id="row5341131742616"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p10534184519273"><a name="p10534184519273"></a><a name="p10534184519273"></a>free</p>
778</td>
779<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
780</tr>
781<tr id="row18341101714263"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p12534184522712"><a name="p12534184522712"></a><a name="p12534184522712"></a>posix_memalign</p>
782</td>
783<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
784</tr>
785<tr id="row18341121732619"><td class="cellrowborder" rowspan="2" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p125341945182720"><a name="p125341945182720"></a><a name="p125341945182720"></a>mman</p>
786</td>
787<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p7534184532717"><a name="p7534184532717"></a><a name="p7534184532717"></a>mmap</p>
788</td>
789<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 ">-</td>
790</tr>
791<tr id="row534131772614"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p12534184513273"><a name="p12534184513273"></a><a name="p12534184513273"></a>munmap</p>
792</td>
793<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
794</tr>
795<tr id="row434101742618"><td class="cellrowborder" rowspan="3" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p253419457279"><a name="p253419457279"></a><a name="p253419457279"></a>time</p>
796</td>
797<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p16534124510274"><a name="p16534124510274"></a><a name="p16534124510274"></a>gettimeofday</p>
798</td>
799<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 ">-</td>
800</tr>
801<tr id="row53411917172619"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p11534124522712"><a name="p11534124522712"></a><a name="p11534124522712"></a>strftime</p>
802</td>
803<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
804</tr>
805<tr id="row5341101712617"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p19535845152713"><a name="p19535845152713"></a><a name="p19535845152713"></a>time</p>
806</td>
807<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
808</tr>
809<tr id="row1334131792612"><td class="cellrowborder" rowspan="6" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p105357458277"><a name="p105357458277"></a><a name="p105357458277"></a>stdio</p>
810</td>
811<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p75354454278"><a name="p75354454278"></a><a name="p75354454278"></a>printf</p>
812</td>
813<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p4535134517270"><a name="p4535134517270"></a><a name="p4535134517270"></a>目前不支持文件系统,文件操作只支持标准输入输出。</p>
814</td>
815</tr>
816<tr id="row63421517192616"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p2535154592716"><a name="p2535154592716"></a><a name="p2535154592716"></a>scanf</p>
817</td>
818<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
819</tr>
820<tr id="row83421817132613"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p105351045132712"><a name="p105351045132712"></a><a name="p105351045132712"></a>snprintf</p>
821</td>
822<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
823</tr>
824<tr id="row434291782619"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p12535545132715"><a name="p12535545132715"></a><a name="p12535545132715"></a>sprintf</p>
825</td>
826<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
827</tr>
828<tr id="row19342517122616"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p3535245132711"><a name="p3535245132711"></a><a name="p3535245132711"></a>vsnprintf</p>
829</td>
830<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
831</tr>
832<tr id="row1342161792613"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p353518454270"><a name="p353518454270"></a><a name="p353518454270"></a>vsprintf</p>
833</td>
834<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
835</tr>
836<tr id="row734291715264"><td class="cellrowborder" rowspan="2" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p13535045172712"><a name="p13535045172712"></a><a name="p13535045172712"></a>errno</p>
837</td>
838<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p25351645132719"><a name="p25351645132719"></a><a name="p25351645132719"></a>errno</p>
839</td>
840<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 ">-</td>
841</tr>
842<tr id="row11342181711269"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p11535164515276"><a name="p11535164515276"></a><a name="p11535164515276"></a>strerror</p>
843</td>
844<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
845</tr>
846<tr id="row5342151710264"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p10535945152714"><a name="p10535945152714"></a><a name="p10535945152714"></a>exit</p>
847</td>
848<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p8535124519274"><a name="p8535124519274"></a><a name="p8535124519274"></a>abort</p>
849</td>
850<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 ">-</td>
851</tr>
852<tr id="row11342117182611"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p85358458277"><a name="p85358458277"></a><a name="p85358458277"></a>unistd</p>
853</td>
854<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p1753517452273"><a name="p1753517452273"></a><a name="p1753517452273"></a>getpid</p>
855</td>
856<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 ">-</td>
857</tr>
858<tr id="row1034281772615"><td class="cellrowborder" rowspan="4" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p1553514592714"><a name="p1553514592714"></a><a name="p1553514592714"></a>locale</p>
859</td>
860<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p753574512278"><a name="p753574512278"></a><a name="p753574512278"></a>setlocale</p>
861</td>
862<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 ">-</td>
863</tr>
864<tr id="row334220171263"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p115353451276"><a name="p115353451276"></a><a name="p115353451276"></a>strcoll</p>
865</td>
866<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
867</tr>
868<tr id="row13343151762618"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p95351145142716"><a name="p95351145142716"></a><a name="p95351145142716"></a>strxfrm</p>
869</td>
870<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
871</tr>
872<tr id="row173433172262"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p0535104512273"><a name="p0535104512273"></a><a name="p0535104512273"></a>strtod</p>
873</td>
874<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
875</tr>
876<tr id="row2343131732614"><td class="cellrowborder" rowspan="3" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p95351945132716"><a name="p95351945132716"></a><a name="p95351945132716"></a>multibyte</p>
877</td>
878<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p25351345122715"><a name="p25351345122715"></a><a name="p25351345122715"></a>mbrtowc</p>
879</td>
880<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 ">-</td>
881</tr>
882<tr id="row1234321772614"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p185354453273"><a name="p185354453273"></a><a name="p185354453273"></a>wcrtomb</p>
883</td>
884<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
885</tr>
886<tr id="row7343151762613"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p115361445112716"><a name="p115361445112716"></a><a name="p115361445112716"></a>wctob</p>
887</td>
888<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
889</tr>
890<tr id="row1034351714262"><td class="cellrowborder" rowspan="4" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p135361645112710"><a name="p135361645112710"></a><a name="p135361645112710"></a>prng</p>
891</td>
892<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p19536134517272"><a name="p19536134517272"></a><a name="p19536134517272"></a>srandom</p>
893</td>
894<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 ">-</td>
895</tr>
896<tr id="row73431717102610"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p17536134518272"><a name="p17536134518272"></a><a name="p17536134518272"></a>initstate</p>
897</td>
898<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
899</tr>
900<tr id="row17343181742615"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p2536144515271"><a name="p2536144515271"></a><a name="p2536144515271"></a>setstate</p>
901</td>
902<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
903</tr>
904<tr id="row16343121711263"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p185362459278"><a name="p185362459278"></a><a name="p185362459278"></a>random</p>
905</td>
906<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
907</tr>
908<tr id="row63431217102612"><td class="cellrowborder" rowspan="17" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p1153618451278"><a name="p1153618451278"></a><a name="p1153618451278"></a>string</p>
909</td>
910<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p1553620456277"><a name="p1553620456277"></a><a name="p1553620456277"></a>memchr</p>
911</td>
912<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 ">-</td>
913</tr>
914<tr id="row93431217112613"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p14536154510275"><a name="p14536154510275"></a><a name="p14536154510275"></a>memcmp</p>
915</td>
916<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
917</tr>
918<tr id="row17344417112619"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p153684515275"><a name="p153684515275"></a><a name="p153684515275"></a>memcpy</p>
919</td>
920<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
921</tr>
922<tr id="row1934421712265"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1653694592712"><a name="p1653694592712"></a><a name="p1653694592712"></a>memmove</p>
923</td>
924<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
925</tr>
926<tr id="row934411712267"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p2536114510274"><a name="p2536114510274"></a><a name="p2536114510274"></a>memset</p>
927</td>
928<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
929</tr>
930<tr id="row163441117142619"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p105361345112715"><a name="p105361345112715"></a><a name="p105361345112715"></a>strchr</p>
931</td>
932<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
933</tr>
934<tr id="row1434451715262"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p175366451279"><a name="p175366451279"></a><a name="p175366451279"></a>strcmp</p>
935</td>
936<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
937</tr>
938<tr id="row534471762616"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p353694514273"><a name="p353694514273"></a><a name="p353694514273"></a>strcpy</p>
939</td>
940<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
941</tr>
942<tr id="row334461752611"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1753694515274"><a name="p1753694515274"></a><a name="p1753694515274"></a>strlen</p>
943</td>
944<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
945</tr>
946<tr id="row834419172265"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p0536745102720"><a name="p0536745102720"></a><a name="p0536745102720"></a>strncmp</p>
947</td>
948<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
949</tr>
950<tr id="row1734415175268"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p55361345192717"><a name="p55361345192717"></a><a name="p55361345192717"></a>strncpy</p>
951</td>
952<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
953</tr>
954<tr id="row183445174264"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p115365457273"><a name="p115365457273"></a><a name="p115365457273"></a>strnlen</p>
955</td>
956<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
957</tr>
958<tr id="row1534401712611"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p19537245112712"><a name="p19537245112712"></a><a name="p19537245112712"></a>strrchr</p>
959</td>
960<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
961</tr>
962<tr id="row13451617142620"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p125371456272"><a name="p125371456272"></a><a name="p125371456272"></a>strstr</p>
963</td>
964<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
965</tr>
966<tr id="row15345181762614"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p95371845142718"><a name="p95371845142718"></a><a name="p95371845142718"></a>wcschr</p>
967</td>
968<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
969</tr>
970<tr id="row10345151718267"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p0537124512279"><a name="p0537124512279"></a><a name="p0537124512279"></a>wcslen</p>
971</td>
972<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
973</tr>
974<tr id="row2345111710263"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p145371645142718"><a name="p145371645142718"></a><a name="p145371645142718"></a>wmemchr</p>
975</td>
976<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
977</tr>
978<tr id="row12345131715263"><td class="cellrowborder" rowspan="13" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p753714502717"><a name="p753714502717"></a><a name="p753714502717"></a>ctype</p>
979</td>
980<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p5537145142720"><a name="p5537145142720"></a><a name="p5537145142720"></a>isalpha</p>
981</td>
982<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 ">-</td>
983</tr>
984<tr id="row1434581792614"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p0537184511274"><a name="p0537184511274"></a><a name="p0537184511274"></a>isascii</p>
985</td>
986<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
987</tr>
988<tr id="row5345417182620"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p8537114513278"><a name="p8537114513278"></a><a name="p8537114513278"></a>isdigit</p>
989</td>
990<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
991</tr>
992<tr id="row8345117122618"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p8537204582712"><a name="p8537204582712"></a><a name="p8537204582712"></a>islower</p>
993</td>
994<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
995</tr>
996<tr id="row034551782617"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p253716455273"><a name="p253716455273"></a><a name="p253716455273"></a>isprint</p>
997</td>
998<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
999</tr>
1000<tr id="row4345101713267"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1053713455279"><a name="p1053713455279"></a><a name="p1053713455279"></a>isspace</p>
1001</td>
1002<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
1003</tr>
1004<tr id="row16345201752616"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p853764562716"><a name="p853764562716"></a><a name="p853764562716"></a>iswctype</p>
1005</td>
1006<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
1007</tr>
1008<tr id="row33455179264"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p18537114522715"><a name="p18537114522715"></a><a name="p18537114522715"></a>iswdigit</p>
1009</td>
1010<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
1011</tr>
1012<tr id="row83461317192614"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p16537154512710"><a name="p16537154512710"></a><a name="p16537154512710"></a>iswlower</p>
1013</td>
1014<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
1015</tr>
1016<tr id="row93461117152620"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p353713458276"><a name="p353713458276"></a><a name="p353713458276"></a>iswspace</p>
1017</td>
1018<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
1019</tr>
1020<tr id="row19346161711268"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p75371145202717"><a name="p75371145202717"></a><a name="p75371145202717"></a>iswupper</p>
1021</td>
1022<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
1023</tr>
1024<tr id="row123461517162613"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p3537245152710"><a name="p3537245152710"></a><a name="p3537245152710"></a>towupper</p>
1025</td>
1026<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
1027</tr>
1028<tr id="row1734671714268"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p175381245172715"><a name="p175381245172715"></a><a name="p175381245172715"></a>towlower</p>
1029</td>
1030<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
1031</tr>
1032<tr id="row6346117112615"><td class="cellrowborder" rowspan="16" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p2538174512714"><a name="p2538174512714"></a><a name="p2538174512714"></a>math</p>
1033</td>
1034<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p19538184572712"><a name="p19538184572712"></a><a name="p19538184572712"></a>atan</p>
1035</td>
1036<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 ">-</td>
1037</tr>
1038<tr id="row8346131782613"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p15381945172717"><a name="p15381945172717"></a><a name="p15381945172717"></a>ceil</p>
1039</td>
1040<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
1041</tr>
1042<tr id="row734617176261"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p953844582716"><a name="p953844582716"></a><a name="p953844582716"></a>ceilf</p>
1043</td>
1044<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
1045</tr>
1046<tr id="row134610174264"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p053824511271"><a name="p053824511271"></a><a name="p053824511271"></a>copysignl</p>
1047</td>
1048<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
1049</tr>
1050<tr id="row13346917152610"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p13538104522717"><a name="p13538104522717"></a><a name="p13538104522717"></a>exp</p>
1051</td>
1052<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
1053</tr>
1054<tr id="row334661712269"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p5538154512710"><a name="p5538154512710"></a><a name="p5538154512710"></a>fabs</p>
1055</td>
1056<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
1057</tr>
1058<tr id="row2347181722616"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p2538184522716"><a name="p2538184522716"></a><a name="p2538184522716"></a>floor</p>
1059</td>
1060<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
1061</tr>
1062<tr id="row123471517122616"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1453874562717"><a name="p1453874562717"></a><a name="p1453874562717"></a>frexp</p>
1063</td>
1064<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
1065</tr>
1066<tr id="row153471917112616"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p14538134512271"><a name="p14538134512271"></a><a name="p14538134512271"></a>frexpl</p>
1067</td>
1068<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
1069</tr>
1070<tr id="row234771717261"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p10538245102714"><a name="p10538245102714"></a><a name="p10538245102714"></a>log</p>
1071</td>
1072<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
1073</tr>
1074<tr id="row1334711179265"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p185381245142719"><a name="p185381245142719"></a><a name="p185381245142719"></a>log2</p>
1075</td>
1076<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
1077</tr>
1078<tr id="row103471317132612"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p20538144512275"><a name="p20538144512275"></a><a name="p20538144512275"></a>pow</p>
1079</td>
1080<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
1081</tr>
1082<tr id="row133472178262"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p35389459277"><a name="p35389459277"></a><a name="p35389459277"></a>roundf</p>
1083</td>
1084<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
1085</tr>
1086<tr id="row234731713261"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p4538154522715"><a name="p4538154522715"></a><a name="p4538154522715"></a>scalbn</p>
1087</td>
1088<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
1089</tr>
1090<tr id="row1347917182619"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p85381845192718"><a name="p85381845192718"></a><a name="p85381845192718"></a>scalbnl</p>
1091</td>
1092<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
1093</tr>
1094<tr id="row1134717178267"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p11538845102718"><a name="p11538845102718"></a><a name="p11538845102718"></a>sqrt</p>
1095</td>
1096<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
1097</tr>
1098<tr id="row13348101715261"><td class="cellrowborder" rowspan="14" align="left" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p195391445102713"><a name="p195391445102713"></a><a name="p195391445102713"></a>stdlib</p>
1099</td>
1100<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p1153954552713"><a name="p1153954552713"></a><a name="p1153954552713"></a>abs</p>
1101</td>
1102<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 ">-</td>
1103</tr>
1104<tr id="row4348101732615"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1853910450272"><a name="p1853910450272"></a><a name="p1853910450272"></a>atof</p>
1105</td>
1106<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
1107</tr>
1108<tr id="row12348111782617"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p12539124562717"><a name="p12539124562717"></a><a name="p12539124562717"></a>atoi</p>
1109</td>
1110<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
1111</tr>
1112<tr id="row123482178261"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p95391945102713"><a name="p95391945102713"></a><a name="p95391945102713"></a>atol</p>
1113</td>
1114<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
1115</tr>
1116<tr id="row163481117142610"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p35391745172718"><a name="p35391745172718"></a><a name="p35391745172718"></a>atoll</p>
1117</td>
1118<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
1119</tr>
1120<tr id="row6348217132613"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p4539164511276"><a name="p4539164511276"></a><a name="p4539164511276"></a>bsearch</p>
1121</td>
1122<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
1123</tr>
1124<tr id="row12348191714269"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p195391245102717"><a name="p195391245102717"></a><a name="p195391245102717"></a>div</p>
1125</td>
1126<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
1127</tr>
1128<tr id="row1634810170260"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p10539124513274"><a name="p10539124513274"></a><a name="p10539124513274"></a>ecvt</p>
1129</td>
1130<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
1131</tr>
1132<tr id="row103481517182617"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p75392457277"><a name="p75392457277"></a><a name="p75392457277"></a>imaxabs</p>
1133</td>
1134<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
1135</tr>
1136<tr id="row1834817175260"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p854014552719"><a name="p854014552719"></a><a name="p854014552719"></a>llabs</p>
1137</td>
1138<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
1139</tr>
1140<tr id="row1349121792612"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p1154054562718"><a name="p1154054562718"></a><a name="p1154054562718"></a>qsort</p>
1141</td>
1142<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
1143</tr>
1144<tr id="row15349117192614"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p14540645172719"><a name="p14540645172719"></a><a name="p14540645172719"></a>strtoul</p>
1145</td>
1146<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
1147</tr>
1148<tr id="row134910176267"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p135401445172712"><a name="p135401445172712"></a><a name="p135401445172712"></a>strtol</p>
1149</td>
1150<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
1151</tr>
1152<tr id="row183494173268"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p3540114519272"><a name="p3540114519272"></a><a name="p3540114519272"></a>wcstod</p>
1153</td>
1154<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 ">-</td>
1155</tr>
1156</tbody>
1157</table>
1158
1159>![](public_sys-resources/icon-caution.gif) **注意:**
1160>1.  不支持文件系统、控制台。
1161>2.  不支持fstat,fsync,writev接口。
1162
1163## 安全函数库<a name="section127921457151719"></a>
1164
1165### 概述<a name="section5848918131818"></a>
1166
1167危险函数依赖于程序员对参数进行检查或保证空间能足够容纳所产生的结果,函数本身不对这些情况进行判断,即使有问题也不会给出错误的指示。C11标准中对于过时的不安全的危险函数定义了对应的安全函数(\_s版本的函数),相比危险函数,安全函数对照C11标准进行了相应的安全增强,会对入参以及不同的错误情况进行判断,降低操作不当所引入的安全风险。下表列举了危险函数以及对应的安全函数,TA代码中涉及到相关危险函数的必须使用安全函数。
1168
1169**表 10**  危险函数以及对应的安全函数
1170
1171<a name="table18216829674"></a>
1172<table><thead align="left"><tr id="row1221612296715"><th class="cellrowborder" valign="top" width="50%" id="mcps1.2.3.1.1"><p id="p1280043317715"><a name="p1280043317715"></a><a name="p1280043317715"></a>危险函数</p>
1173</th>
1174<th class="cellrowborder" valign="top" width="50%" id="mcps1.2.3.1.2"><p id="p880019332710"><a name="p880019332710"></a><a name="p880019332710"></a>安全函数</p>
1175</th>
1176</tr>
1177</thead>
1178<tbody><tr id="row122166291776"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p198006331074"><a name="p198006331074"></a><a name="p198006331074"></a>memcpy</p>
1179</td>
1180<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p16800533473"><a name="p16800533473"></a><a name="p16800533473"></a>memcpy_s</p>
1181</td>
1182</tr>
1183<tr id="row421610291977"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p080012331073"><a name="p080012331073"></a><a name="p080012331073"></a>memmove</p>
1184</td>
1185<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p1680013331779"><a name="p1680013331779"></a><a name="p1680013331779"></a>memmove_s</p>
1186</td>
1187</tr>
1188<tr id="row152161229975"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p1480013336712"><a name="p1480013336712"></a><a name="p1480013336712"></a>memset</p>
1189</td>
1190<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p4800103314713"><a name="p4800103314713"></a><a name="p4800103314713"></a>memset_s</p>
1191</td>
1192</tr>
1193<tr id="row02163297719"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p1580017338710"><a name="p1580017338710"></a><a name="p1580017338710"></a>strcpy</p>
1194</td>
1195<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p20800233575"><a name="p20800233575"></a><a name="p20800233575"></a>strcpy_s</p>
1196</td>
1197</tr>
1198<tr id="row132161629777"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p680016331977"><a name="p680016331977"></a><a name="p680016331977"></a>strncpy</p>
1199</td>
1200<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p1880013335719"><a name="p1880013335719"></a><a name="p1880013335719"></a>strncpy_s</p>
1201</td>
1202</tr>
1203<tr id="row1821642918715"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p180010331175"><a name="p180010331175"></a><a name="p180010331175"></a>strcat</p>
1204</td>
1205<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p158003331671"><a name="p158003331671"></a><a name="p158003331671"></a>strcat_s</p>
1206</td>
1207</tr>
1208<tr id="row72167299712"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p780014331373"><a name="p780014331373"></a><a name="p780014331373"></a>strncat</p>
1209</td>
1210<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p188017331171"><a name="p188017331171"></a><a name="p188017331171"></a>strncat_s</p>
1211</td>
1212</tr>
1213<tr id="row17217202917714"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p780113331478"><a name="p780113331478"></a><a name="p780113331478"></a>strtok</p>
1214</td>
1215<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p128013333711"><a name="p128013333711"></a><a name="p128013333711"></a>strtok_s</p>
1216</td>
1217</tr>
1218<tr id="row1021717291676"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p980111331072"><a name="p980111331072"></a><a name="p980111331072"></a>snprintf</p>
1219</td>
1220<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p98011331277"><a name="p98011331277"></a><a name="p98011331277"></a>snprintf_s</p>
1221</td>
1222</tr>
1223<tr id="row92174291974"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p380114333720"><a name="p380114333720"></a><a name="p380114333720"></a>vsnprintf</p>
1224</td>
1225<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p20801183316710"><a name="p20801183316710"></a><a name="p20801183316710"></a>vsnprintf_s</p>
1226</td>
1227</tr>
1228</tbody>
1229</table>
1230
1231详细描述请参考头文件<securec.h\>。
1232
1233安全函数包含部分如下特性:
1234
1235-   强化边界检查:在接口参数中增加一个buffer长度的参数,在长度参数正确情况下不会出现溢出。
1236-   保证结果字符串以’\\0’结尾,避免访问buffer边界之外的信息。
1237-   发现缓冲区溢出发生,将目的缓冲区的首字节置零。
1238-   增加错误返回值,便于程序员快速进行错误定位。
1239-   增强入参检查。
1240-   增加入参的内存重叠检查(memcpy\_sp宏中对于常量拷贝不进行内存重叠检查)。
1241-   定义SECUREC\_STRING\_MAX\_LEN和SECUREC\_MEM\_MAX\_LEN宏,可以通过其限定字符串和内存操作时的最大长度。
1242-   定义SECUREC\_ERROR\_INVALID\_PARAMTER、SECUREC\_ERROR\_INVALID\_RANGE和SECUREC\_ERROR\_BUFFER\_OVERLAP宏,其会在参数出错时进行统一处理,用户可自定义发生错误时的函数处理行为。
1243
1244### 内存复制<a name="section1620304312183"></a>
1245
1246memcpy\_s:
1247
1248```
1249errno_t memcpy_s(void* dest, size_t destMax, const void* src, size_t count);
1250```
1251
1252复制源缓冲区的数据到目的缓冲区。
1253
1254>![](public_sys-resources/icon-caution.gif) **注意:**
1255>-   与系统函数相比:1)多了一个参数:目的缓冲区总大小;  2)系统函数返回值为指针,安全函数返回值为整型。
1256>-   调用函数时,注意判断返回值是否成功,否则有可能操作结果和预期不一致。
1257>-   某些出错情况下,会对目的缓冲区清0,具体参考如上**表1**。
1258>-   进行字符串拷贝时,不会自动在末尾添加结束符。(对字符串操作,建议使用字符串操作函数)
1259
1260-   示例
1261
1262<figure>
1263
1264```
1265 #include "securec.h"
1266 #include <string.h>
1267
1268 #define BUFFER_SIZE 11
1269
1270 int main()
1271 {
1272     char str1[BUFFER_SIZE] = "0123456789";
1273     char str2[BUFFER_SIZE] = {0x00};
1274     errno_t rc =  EOK;
1275
1276     rc = memcpy_s(str2,  BUFFER_SIZE, str1, BUFFER_SIZE - 1);
1277     printf("rc = %d,  %s\n", rc, str2);
1278
1279     /* count is bigger than destMax, return ERANGE_AND_RESET  and dest is reset. */
1280     rc = memcpy_s(str2,  BUFFER_SIZE, str1, BUFFER_SIZE + 1);
1281     printf("rc = %d, %s\n", rc,  str2);
1282
1283     /* initialize */
1284     rc = memcpy_s(str2,  BUFFER_SIZE, str1, BUFFER_SIZE - 1);
1285     printf("rc = %d, %s\n", rc,  str2);
1286
1287     /* overlap, return EOVERLAP_AND_RESET and dest is reset.  */
1288     rc = memcpy_s(str2,  BUFFER_SIZE, str2 + 2, BUFFER_SIZE - 1);
1289     printf("rc = %d, %s\n", rc,  str2);
1290
1291     return 0;
1292 }
1293运行结果:
1294rc =  0, 0123456789
1295rc =  162
1296rc =  0, 0123456789
1297rc =  182
1298```
1299
1300</figure>
1301
1302memmove\_s:
1303
1304```
1305errno_t memmove_s(void* dest,size_t destMax, const void* src, size_t count);
1306```
1307
1308移动源缓冲区的数据到目的缓冲区
1309
1310>![](public_sys-resources/icon-caution.gif) **注意:**
1311>-   与系统函数相比:
1312>    -   多了一个参数:目的缓冲区总大小;
1313>    -   系统函数返回值为指针,安全函数返回值为整型。
1314>-   调用函数时,注意判断返回值是否成功,否则有可能操作结果和预期不一致。
1315>-   某些出错情况下,会对目的缓冲区清0,具体参考如上**表2**。
1316
1317-   示例
1318
1319<figure>
1320
1321```
1322 #include "securec.h"
1323 #include <string.h>
1324
1325 #define BUFFER_SIZE 11
1326
1327 int main()
1328 {
1329     char str[BUFFER_SIZE] = "0123456789";
1330     errno_t rc =  EOK;
1331
1332     printf("Before:  %s\n", str);
1333
1334     /* Move six bytes from the start of the  string
1335     * to a new position shifted  by one byte. To protect against
1336     * buffer overrun, the  secure version of memmove requires the
1337     * the length of the  destination string to be specified.
1338     */
1339
1340     rc = memmove_s(str,  BUFFER_SIZE, str + 1, 6);
1341     printf("After: rc = %d, %s\n", rc,  str);
1342
1343     /* count is bigger than destMax, return ERANGE_AND_RESET  and dest is reset. */
1344     rc = memmove_s(str,  BUFFER_SIZE, str + 1, BUFFER_SIZE + 100);
1345     printf("Later: rc = %d, %s\n",  rc, str);
1346
1347     return 0;
1348 }
1349运行结果:
1350Before: 0123456789
1351After: rc = 0,  123456789
1352Later: rc =  162
1353```
1354
1355</figure>
1356
1357### 内存初始化<a name="section9113185921817"></a>
1358
1359memset\_s:
1360
1361```
1362errno_t memset_s(void* dest, size_t destMax, int c, size_t count);
1363```
1364
1365复制源缓冲区的数据到目的缓冲区
1366
1367>![](public_sys-resources/icon-caution.gif) **注意:**
1368>-   与系统函数相比:1)多了一个参数:目的缓冲区总大小;  2)系统函数返回值为指针,安全函数返回值为整型。
1369>-   调用函数时,注意判断返回值是否成功,否则有可能操作结果和预期不一致。
1370
1371-   示例
1372
1373<figure>
1374
1375```
1376 #include "securec.h"
1377 #include <string.h>
1378
1379 #define BUFFER_SIZE 40
1380
1381 int main()
1382 {
1383     char buffer[BUFFER_SIZE] =  "This is a test of the memset  function";
1384     errno_t rc =  EOK;
1385
1386     printf( "Before: %s\n", buffer );
1387
1388     rc = memset_s(buffer,  BUFFER_SIZE, '*', 20 );
1389     printf( "After: rc = %d, %s\n", rc, buffer  );
1390
1391     /* count is bigger than destMax, return ERANGE_AND_RESET  and destMax size is set. */
1392     rc = memset_s(buffer,  BUFFER_SIZE, '*', BUFFER_SIZE + 1 );
1393     printf( "Later: rc = %d, %s\n", rc, buffer  );
1394
1395     return  0;
1396 }
1397
1398 运行结果:
1399 Before: This is a test of the memset function
1400 After: rc = 0, ********************e memset  function
1401 Later: rc = 162,  ****************************************
1402```
1403
1404</figure>
1405
1406### 字符串复制<a name="section320518115198"></a>
1407
1408strcpy\_s:
1409
1410```
1411errno_t strcpy_s(char* strDest, size_t destMax, const char* strSrc);
1412```
1413
1414复制源字符串到目的缓冲区
1415
1416>![](public_sys-resources/icon-caution.gif) **注意:**
1417>-   与系统函数相比:1)、多了一个参数:目的缓冲区总大小; 2)、系统函数返回值为指针,安全函数返回值为整型。
1418>-   调用函数时,注意判断返回值是否成功,否则有可能操作结果和预期不一致。
1419>-   某些出错情况下,会对目的缓冲区首字符置0,具体参考如上**表1**。
1420>源字符串必须含有结束符。
1421
1422-   示例
1423
1424<figure>
1425
1426```
1427 #include "securec.h"
1428 #include <stdio.h>
1429
1430 #define SMALL_BUF_SIZE 10
1431 #define BIG_BUF_SIZE 100
1432
1433 int main()
1434 {
1435     char str1[BIG_BUF_SIZE] = {0x00};
1436     char str2[SMALL_BUF_SIZE] = {0x00};
1437     char *str3 = str1 +  4;
1438     errno_t rc =  EOK;
1439
1440     rc = strcpy_s(str1,  BIG_BUF_SIZE, "Security Design  Department");
1441     printf("rc = %d,  %s\n", rc, str1);
1442
1443     /* strSrc length + 1 is bigger than destMax, return  ERANGE_AND_RESET and strDest is reset. */
1444     rc = strcpy_s(str2,  SMALL_BUF_SIZE, "Security Design");
1445     printf("rc = %d,  %s\n", rc, str2);
1446
1447     memset_s(str1,  BIG_BUF_SIZE, 0x41, BIG_BUF_SIZE);
1448     /* overlap, return EOVERLAP_AND_RESET and strDest is reset.  */
1449     rc = strcpy_s(str1,  BIG_BUF_SIZE, str3);
1450     printf("rc = %d,  %s\n", rc, str1);
1451
1452     return 0;
1453 }
1454
1455运行结果:
1456rc  = 0, Security Design Department
1457rc  = 162,
1458rc  = 182,
1459```
1460
1461</figure>
1462
1463strncpy\_s:
1464
1465```
1466errno_t strncpy_s(char* strDest, size_t destMax, const char* strSrc, size_t count);
1467```
1468
1469复制指定长度的源字符串到目的缓冲区。
1470
1471>![](public_sys-resources/icon-caution.gif) **注意:**
1472>-   与系统函数相比:1)多了一个参数:目的缓冲区总大小; 2)系统函数返回值为指针,安全函数返回值为整型。
1473>-   调用函数时,注意判断返回值是否成功,否则有可能操作结果和预期不一致。
1474>-   某些出错情况下,会对目的缓冲区首字符置0,具体参考如上**表2**。
1475>-   源字符串必须含有结束符。
1476>-   调用该函数时建议传入的参数destMax  大于 count以保证有截断功能。
1477>-   安全函数strncpy\_s执行完后保证strDest有’\\0’结尾,而危险函数strncpy不保证。
1478>-   当  count 大于 strlen\(strSrc\)  时,  strncpy函数会复制完字符串后在strDest中填充count-strlen\(strSrc\)个’\\0’字符,而strncpy\_s函数不做填充。
1479
1480-   示例
1481
1482<figure>
1483
1484```
1485 #define SMALL_BUF_SIZE 10
1486 #define BIG_BUF_SIZE 100
1487
1488 int main()
1489 {
1490     char str1[BIG_BUF_SIZE] =  {0x00};
1491     char str2[BIG_BUF_SIZE] =  "security design  department";
1492     char *str3 = str1 +  4;
1493     char str4[SMALL_BUF_SIZE] =  {0x00};
1494     errno_t rc =  EOK;
1495
1496     rc = strncpy_s(str1,  BIG_BUF_SIZE, str2, 15);
1497     printf("rc = %d, %s\n", rc, str1);
1498
1499     /* count is bigger than destMax, return ERANGE_AND_RESET  and dest is reset. */
1500     rc = strncpy_s(str4,  SMALL_BUF_SIZE, "security Design Department", 15);
1501     printf("rc = %d, %s\n", rc, str4);
1502
1503     memset_s(str1,  BIG_BUF_SIZE, 0x41, BIG_BUF_SIZE);
1504     /* overlap, return EOVERLAP_AND_RESET and dest is reset.  */
1505     rc = strncpy_s(str1,  BIG_BUF_SIZE, str3, 15);
1506     printf("rc = %d, %s\n", rc, str1);
1507
1508     return 0;
1509 }
1510
1511运行结果:
1512rc =  0, security design
1513rc =  162,
1514rc =  182,
1515```
1516
1517</figure>
1518
1519### 字符串连接<a name="section3307826101911"></a>
1520
1521strcat\_s:
1522
1523```
1524errno_t strcat_s(char* strDest, size_t destMax, const char* strSrc);
1525```
1526
1527将源字符串连接到目的字符串后面。
1528
1529>![](public_sys-resources/icon-caution.gif) **注意:**
1530>-   与系统函数相比:
1531>    -   多了一个参数:目的缓冲区总大小;
1532>    -   系统函数返回值为指针,安全函数返回值为整型。
1533>-   调用函数时,注意判断返回值是否成功,否则有可能操作结果和预期不一致。
1534>-   某些出错情况下,会对目的缓冲区的首字符置0,具体参考如上**表1**。
1535
1536-   示例
1537
1538<figure>
1539
1540```
1541 #include "securec.h"
1542 #include <stdio.h>
1543
1544 #define BUFFER_SIZE  64
1545
1546 int main()
1547 {
1548     char   str1[BUFFER_SIZE] = {’’};
1549     char   str2[BUFFER_SIZE] = {’b’};
1550     errno_t rc = EOK;
1551
1552     rc = strcat_s(str1,  3, str2);
1553     printf("rc = %d, %s\n", rc, str1);
1554
1555
1556     /*strdest in destMax don’t have ‘\0’*/
1557     memset_s(str1, BUFFER_SIZE,'a',4);
1558     memset_s(str2, BUFFER_SIZE,'b',4);
1559     rc = strcat_s(str1, 4,  str2);
1560     printf("rc = %d, %s\n", rc, str1);
1561
1562     /*destmax isn’t enough for strSrc*/
1563     memset_s(str1, BUFFER_SIZE,'a',4);
1564     memset_s(str2, BUFFER_SIZE,'b',4);
1565     rc = strcat_s(str1,8, str2);
1566     printf("rc = %d, %s\n", rc, str1);
1567
1568     /*dest , src overlap*/
1569     rc = strncat_s(str2,8, str2+2,1);
1570     printf("rc = %d, %s\n", rc, str2);
1571
1572     return 0;
1573 }
1574
1575运行结果:
1576rc = 0, ab
1577rc = 150,
1578rc = 162,
1579rc = 182,
1580```
1581
1582</figure>
1583
1584strncat\_s:
1585
1586```
1587errno_t strncat_s(char* strDest, size_t destMax, const char* strSrc, size_t count);
1588```
1589
1590将指定长度的源字符串连接到目的字符串后面。
1591
1592>![](public_sys-resources/icon-caution.gif) **注意:**
1593>-   与系统函数相比:
1594>    -   多了一个参数:目的缓冲区总大小;
1595>    -   系统函数返回值为指针,安全函数返回值为整型。
1596>-   调用函数时,注意判断返回值是否成功,否则有可能操作结果和预期不一致。
1597>-   某些出错情况下,会对目的缓冲区的首字符置0,具体参考如上**表2**。
1598
1599-   示例
1600
1601<figure>
1602
1603```
1604 #include "securec.h"
1605 #include <stdio.h>
1606
1607 #define BUFFER_SIZE  64
1608
1609 int main()
1610 {
1611     char   str1[BUFFER_SIZE] = {’’};
1612     char   str2[BUFFER_SIZE] = {’b’};
1613     errno_t rc = EOK;
1614
1615     rc = strncat_s(str1, 3, str2,  1);
1616     printf("rc = %d, %s\n", rc , str1);
1617
1618     /*strdest in destMax don’t have  ‘\0’*/
1619     memset_s(str1, BUFFER_SIZE,’a’,4);
1620     memset_s(str2, BUFFER_SIZE,’b’,4);
1621     rc = strncat_s(str1, 4, str2,  2);
1622     printf("rc  = %d, %s\n", rc ,  str1);
1623
1624     /*destmax isn’t enough for  strSrc*/
1625     memset_s(str1, BUFFER_SIZE,’a’,4);
1626     memset_s(str2, BUFFER_SIZE,’b’,4);
1627     rc = strncat_s(str1,8, str2,5);
1628     printf("rc = %d, %s\n", rc , str1);
1629
1630     /*dest , src overlap*/
1631     rc = strncat_s(str2,8, str2+2,1);
1632     printf("rc = %d, %s\n", rc , str2);
1633
1634     return 0;
1635 }
1636
1637运行结果:
1638rc  = 0, ab
1639rc  = 150,
1640rc  = 162,
1641rc  = 182,
1642```
1643
1644</figure>
1645
1646### 字符串分割<a name="section85731515152610"></a>
1647
1648strtok\_s:
1649
1650```
1651errno_t strtok_s(char* strToken, const char* strDelimit, char** context);
1652```
1653
1654将字符串按照指定的分隔符分割成子字符串。
1655
1656>![](public_sys-resources/icon-caution.gif) **注意:**
1657>-   与系统函数相比:多了一个参数context:保存调用strtok\_s后的下个子字符串的首地址,当不再有子字符串时,context指向被分割字符串结尾。
1658>-   当在被分割字符串中没有找到分隔符时,如果被分割字符串长度大于0,会返回被分割字符串首地址,否则返回NULL。
1659>-   以逗号分隔符为例,顺序调用strtok\_s\(str,&p\), strtok\_s\(NULL,&p\),  strtok\_s\(NULL,&p\)函数的返回值与不同分割字符串的关系如下:
1660
1661**表 11**  返回值与字符串关系
1662
1663<a name="table18556455195912"></a>
1664<table><tbody><tr id="row7556165595917"><td class="cellrowborder" rowspan="2" valign="top"><p id="p156641710803"><a name="p156641710803"></a><a name="p156641710803"></a><strong id="b86641109012"><a name="b86641109012"></a><a name="b86641109012"></a><span>被分割字符串</span></strong></p>
1665</td>
1666<td class="cellrowborder" colspan="3" valign="top"><p id="p1766414101808"><a name="p1766414101808"></a><a name="p1766414101808"></a><strong id="b1866414101608"><a name="b1866414101608"></a><a name="b1866414101608"></a><span>返回值</span></strong></p>
1667</td>
1668</tr>
1669<tr id="row155765565917"><td class="cellrowborder" valign="top"><p id="p146654101808"><a name="p146654101808"></a><a name="p146654101808"></a>strtok_s(str,&amp;p)</p>
1670</td>
1671<td class="cellrowborder" valign="top"><p id="p15665610307"><a name="p15665610307"></a><a name="p15665610307"></a>strtok_s(NULL,&amp;p)</p>
1672</td>
1673<td class="cellrowborder" valign="top"><p id="p17665111019017"><a name="p17665111019017"></a><a name="p17665111019017"></a>strtok_s(NULL,&amp;p)</p>
1674</td>
1675</tr>
1676<tr id="row955745525914"><td class="cellrowborder" valign="top" width="25%"><p id="p19665171014011"><a name="p19665171014011"></a><a name="p19665171014011"></a>str = "aaa"</p>
1677</td>
1678<td class="cellrowborder" valign="top" width="25%"><p id="p46652010100"><a name="p46652010100"></a><a name="p46652010100"></a>"aaa"</p>
1679</td>
1680<td class="cellrowborder" valign="top" width="25%"><p id="p06652101907"><a name="p06652101907"></a><a name="p06652101907"></a>NULL</p>
1681</td>
1682<td class="cellrowborder" valign="top" width="25%"><p id="p466511105013"><a name="p466511105013"></a><a name="p466511105013"></a>_</p>
1683</td>
1684</tr>
1685<tr id="row75571655115910"><td class="cellrowborder" valign="top" width="25%"><p id="p1066512101208"><a name="p1066512101208"></a><a name="p1066512101208"></a><span>str =</span> <span>""</span></p>
1686</td>
1687<td class="cellrowborder" valign="top" width="25%"><p id="p4665181017014"><a name="p4665181017014"></a><a name="p4665181017014"></a><span>NULL</span></p>
1688</td>
1689<td class="cellrowborder" valign="top" width="25%"><p id="p166654101307"><a name="p166654101307"></a><a name="p166654101307"></a>_</p>
1690</td>
1691<td class="cellrowborder" valign="top" width="25%"><p id="p17665111018016"><a name="p17665111018016"></a><a name="p17665111018016"></a>_</p>
1692</td>
1693</tr>
1694<tr id="row4557145516596"><td class="cellrowborder" valign="top" width="25%"><p id="p176651510509"><a name="p176651510509"></a><a name="p176651510509"></a><span>str =</span> <span>","</span></p>
1695</td>
1696<td class="cellrowborder" valign="top" width="25%"><p id="p766510101102"><a name="p766510101102"></a><a name="p766510101102"></a><span>NULL</span></p>
1697</td>
1698<td class="cellrowborder" valign="top" width="25%"><p id="p0665610101"><a name="p0665610101"></a><a name="p0665610101"></a>_</p>
1699</td>
1700<td class="cellrowborder" valign="top" width="25%"><p id="p106657106015"><a name="p106657106015"></a><a name="p106657106015"></a>_</p>
1701</td>
1702</tr>
1703<tr id="row195571055105919"><td class="cellrowborder" valign="top" width="25%"><p id="p26651510407"><a name="p26651510407"></a><a name="p26651510407"></a><span>str =</span> <span>",,"</span></p>
1704</td>
1705<td class="cellrowborder" valign="top" width="25%"><p id="p9665510409"><a name="p9665510409"></a><a name="p9665510409"></a><span>NULL</span></p>
1706</td>
1707<td class="cellrowborder" valign="top" width="25%"><p id="p206657101204"><a name="p206657101204"></a><a name="p206657101204"></a>_</p>
1708</td>
1709<td class="cellrowborder" valign="top" width="25%"><p id="p066541016017"><a name="p066541016017"></a><a name="p066541016017"></a>_</p>
1710</td>
1711</tr>
1712<tr id="row6558115516595"><td class="cellrowborder" valign="top" width="25%"><p id="p1866520102008"><a name="p1866520102008"></a><a name="p1866520102008"></a><span>str =</span> <span>",aaa"</span></p>
1713</td>
1714<td class="cellrowborder" valign="top" width="25%"><p id="p96655102010"><a name="p96655102010"></a><a name="p96655102010"></a><span>"aaa"</span></p>
1715</td>
1716<td class="cellrowborder" valign="top" width="25%"><p id="p06651101902"><a name="p06651101902"></a><a name="p06651101902"></a><span>NULL</span></p>
1717</td>
1718<td class="cellrowborder" valign="top" width="25%"><p id="p18666121018017"><a name="p18666121018017"></a><a name="p18666121018017"></a>_</p>
1719</td>
1720</tr>
1721<tr id="row1955865511594"><td class="cellrowborder" valign="top" width="25%"><p id="p166671012013"><a name="p166671012013"></a><a name="p166671012013"></a><span>str =</span> <span>",,aaa"</span></p>
1722</td>
1723<td class="cellrowborder" valign="top" width="25%"><p id="p1666611018017"><a name="p1666611018017"></a><a name="p1666611018017"></a><span>"aaa"</span></p>
1724</td>
1725<td class="cellrowborder" valign="top" width="25%"><p id="p76665101802"><a name="p76665101802"></a><a name="p76665101802"></a><span>NULL</span></p>
1726</td>
1727<td class="cellrowborder" valign="top" width="25%"><p id="p106666102015"><a name="p106666102015"></a><a name="p106666102015"></a>_</p>
1728</td>
1729</tr>
1730<tr id="row1955805514595"><td class="cellrowborder" valign="top" width="25%"><p id="p466618103014"><a name="p466618103014"></a><a name="p466618103014"></a><span>str =</span> <span>"aaa,"</span></p>
1731</td>
1732<td class="cellrowborder" valign="top" width="25%"><p id="p566615101006"><a name="p566615101006"></a><a name="p566615101006"></a><span>"aaa"</span></p>
1733</td>
1734<td class="cellrowborder" valign="top" width="25%"><p id="p12666210206"><a name="p12666210206"></a><a name="p12666210206"></a><span>NULL</span></p>
1735</td>
1736<td class="cellrowborder" valign="top" width="25%"><p id="p1566617101809"><a name="p1566617101809"></a><a name="p1566617101809"></a>_</p>
1737</td>
1738</tr>
1739<tr id="row755810558594"><td class="cellrowborder" valign="top" width="25%"><p id="p146661510301"><a name="p146661510301"></a><a name="p146661510301"></a><span>str =</span> <span>"aaa,,"</span></p>
1740</td>
1741<td class="cellrowborder" valign="top" width="25%"><p id="p1566641012015"><a name="p1566641012015"></a><a name="p1566641012015"></a><span>"aaa"</span></p>
1742</td>
1743<td class="cellrowborder" valign="top" width="25%"><p id="p1966613107017"><a name="p1966613107017"></a><a name="p1966613107017"></a><span>NULL</span></p>
1744</td>
1745<td class="cellrowborder" valign="top" width="25%"><p id="p1166611108010"><a name="p1166611108010"></a><a name="p1166611108010"></a>_</p>
1746</td>
1747</tr>
1748<tr id="row155915515598"><td class="cellrowborder" valign="top" width="25%"><p id="p1666611101603"><a name="p1666611101603"></a><a name="p1666611101603"></a><span>str =</span> <span>"aaa,bbb"</span></p>
1749</td>
1750<td class="cellrowborder" valign="top" width="25%"><p id="p106663101504"><a name="p106663101504"></a><a name="p106663101504"></a><span>"aaa"</span></p>
1751</td>
1752<td class="cellrowborder" valign="top" width="25%"><p id="p13666610804"><a name="p13666610804"></a><a name="p13666610804"></a><span>"bbb"</span></p>
1753</td>
1754<td class="cellrowborder" valign="top" width="25%"><p id="p126663101003"><a name="p126663101003"></a><a name="p126663101003"></a><span>NULL</span></p>
1755</td>
1756</tr>
1757<tr id="row9559555135919"><td class="cellrowborder" valign="top" width="25%"><p id="p13666131015010"><a name="p13666131015010"></a><a name="p13666131015010"></a><span>str =</span> <span>"aaa,,bbb"</span></p>
1758</td>
1759<td class="cellrowborder" valign="top" width="25%"><p id="p176668102003"><a name="p176668102003"></a><a name="p176668102003"></a><span>"aaa"</span></p>
1760</td>
1761<td class="cellrowborder" valign="top" width="25%"><p id="p196661108012"><a name="p196661108012"></a><a name="p196661108012"></a><span>"bbb"</span></p>
1762</td>
1763<td class="cellrowborder" valign="top" width="25%"><p id="p1366601016011"><a name="p1366601016011"></a><a name="p1366601016011"></a><span>NULL</span></p>
1764</td>
1765</tr>
1766<tr id="row1455915555596"><td class="cellrowborder" valign="top" width="25%"><p id="p8667510002"><a name="p8667510002"></a><a name="p8667510002"></a><span>str =</span> <span>"aaa,bbb,"</span></p>
1767</td>
1768<td class="cellrowborder" valign="top" width="25%"><p id="p196672010506"><a name="p196672010506"></a><a name="p196672010506"></a><span>"aaa"</span></p>
1769</td>
1770<td class="cellrowborder" valign="top" width="25%"><p id="p6667201020015"><a name="p6667201020015"></a><a name="p6667201020015"></a><span>"bbb"</span></p>
1771</td>
1772<td class="cellrowborder" valign="top" width="25%"><p id="p13667161011011"><a name="p13667161011011"></a><a name="p13667161011011"></a><span>NULL</span></p>
1773</td>
1774</tr>
1775<tr id="row175591455145914"><td class="cellrowborder" valign="top" width="25%"><p id="p466713102019"><a name="p466713102019"></a><a name="p466713102019"></a><span>str =</span> <span>"aaa,bbb,,"</span></p>
1776</td>
1777<td class="cellrowborder" valign="top" width="25%"><p id="p1166751019014"><a name="p1166751019014"></a><a name="p1166751019014"></a><span>"aaa"</span></p>
1778</td>
1779<td class="cellrowborder" valign="top" width="25%"><p id="p9667010504"><a name="p9667010504"></a><a name="p9667010504"></a><span>"bbb"</span></p>
1780</td>
1781<td class="cellrowborder" valign="top" width="25%"><p id="p16667910402"><a name="p16667910402"></a><a name="p16667910402"></a><span>NULL</span></p>
1782</td>
1783</tr>
1784</tbody>
1785</table>
1786
1787-   示例
1788
1789<figure>
1790
1791```
1792 #include "securec.h"
1793 #include <stdio.h>
1794
1795 int main()
1796 {
1797     char string1[64]  = "A string\tof ,,tokens\nand some  more tokens";
1798     char string2[64]  = "Another string\n\tparsed at the same  time.";
1799     char seps[] =  " ,\t\n";
1800     char *token1 =  NULL;
1801     char *token2 =  NULL;
1802     char *next_token1  = NULL;
1803     char *next_token2= NULL;
1804
1805     printf( "Tokens:\n" );
1806
1807     /* Establish string and get the first token:  */
1808     token1 = strtok_s(string1, seps,  &next_token1);
1809     token2 = strtok_s(string2, seps,  &next_token2);
1810
1811     /* While there are tokens in "string1" or "string2"  */
1812     while ((token1 !=  NULL) || (token2 != NULL))
1813     {
1814         /* Get next token: */
1815         if (token1 !=  NULL)
1816         {
1817             printf("  %s\n", token1);
1818             token1 = strtok_s(NULL,  seps, &next_token1);
1819         }
1820         if (token2 !=  NULL)
1821         {
1822             printf("        %s\n", token2);
1823             token2 = strtok_s (NULL, seps,  &next_token2);
1824         }
1825     }
1826
1827     return 0;
1828 }
1829
1830运行结果:
1831Tokens:
1832more
1833same
1834some
1835the
1836and
1837at
1838tokens
1839parsed
1840of
1841string
1842string
1843Another
1844time.
1845tokens
1846```
1847
1848</figure>
1849
1850### 格式化输出<a name="section1696173315284"></a>
1851
1852snprintf\_s:
1853
1854```
1855int snprintf_s(char* strDest, size_t destMax, size_t count, const char* format, ...);
1856```
1857
1858将数据按照指定长度格式化输出到目的缓冲区。
1859
1860>![](public_sys-resources/icon-caution.gif) **注意:**
1861>-   与系统函数相比:
1862>    -   多了一个参数:目的缓冲区总大小;
1863>    -   count参数与系统函数的用法存在差异,参见参数表。
1864>-   调用函数时,注意判断返回值是否成功,否则有可能操作结果和预期不一致。
1865>-   某些出错情况下,会对目的缓冲区首字符清0,具体参考如上**表1**。
1866>-   调用该函数时建议传入的参数destMax 大于 count以保证有截断功能。
1867>-   确保输入的源数据与目标缓冲区不存在重叠。
1868>-   输入源数据中若是字符串则必须含有结束符。
1869>输入源数据的类型、个数必须与格式化控制字符串(format)中的类型、个数保持一致。
1870
1871-   示例
1872
1873<figure>
1874
1875```
1876 #include "securec.h"
1877
1878 void  snprintf_sample()
1879 {
1880     char buffer[200]={0};
1881     char     *string = "computer";
1882     wchar_t *wstring =  L"Unicode";
1883
1884     /* format strings. */
1885     int iRet = snprintf_s( buffer, 200, 20,  "%s,%ls", string, wstring);
1886     printf("iRet = %d, buffer = %s.\n", iRet,  buffer);
1887
1888     /* test edge. */
1889     printf("------------------\n");
1890     iRet = snprintf_s( buffer, 3, 3, "%s",  "123");
1891     printf("iRet =  %d, buffer = %s.\n", iRet, buffer);
1892
1893     /* test edge. */
1894     printf("------------------\n");
1895     iRet = snprintf_s( buffer, 3, 2, "%s",  "123");
1896     printf("iRet = %d, buffer = %s.\n", iRet,  buffer);
1897
1898
1899     return;
1900 }
1901
1902 int  main()
1903 {
1904     snprintf_sample ();
1905     return 0;
1906 }
1907
1908运行结果:
1909iRet = 16, buffer  = computer,Unicode.
1910iRet = -1, buffer  = .
1911
1912iRet = -1, buffer  = 12.
1913```
1914
1915</figure>
1916
1917vsnprintf\_s:
1918
1919```
1920int vsnprintf_s(char* strDest, size_t destMax, size_t count, const char* format, va_list arglis);
1921```
1922
1923将参数列表\(_va\_list_\)数据按照指定长度格式化输出到目的缓冲区。
1924
1925>![](public_sys-resources/icon-caution.gif) **注意:**
1926>-   与系统函数相比:
1927>    -   多了一个参数:目的缓冲区总大小;
1928>    -   count参数与系统函数的用法存在差异,参见参数表。
1929>-   调用函数时,注意判断返回值是否成功,否则有可能操作结果和预期不一致。
1930>-   某些出错情况下,会对目的缓冲区首字符清0,具体参考如上表2。
1931>-   调用该函数时建议传入的参数destMax 大于 count以保证有截断功能。
1932>-   确保输入的源数据与目标缓冲区不存在重叠。
1933>-   输入源数据中若是字符串则必须含有结束符。
1934>-   输入源数据的类型、个数必须与格式化控制字符串(format)中的类型、个数保持一致。
1935
1936-   示例1
1937
1938<figure>
1939
1940```
1941 #include "securec.h"
1942
1943 void FormatOutput(char* formatstring, ...)
1944 {
1945     va_list args;
1946     int nSize =  0;
1947     char buff[10];
1948     memset_s(buff,sizeof(buff), 0, sizeof(buff));
1949     va_start(args,  formatstring);
1950     nSize = vsnprintf_s( buff, sizeof(buff), 8,  formatstring, args);
1951     printf("nSize: %d,  buff: %s\n", nSize, buff);
1952 }
1953
1954 int main()
1955 {
1956     FormatOutput("%s  %s", "Hi", "there");
1957     FormatOutput("%s  %s", "Hi", "there!");
1958
1959     return 0;
1960 }
1961
1962运行结果:
1963nSize: 8, buff: Hi there
1964nSize: -1, buff: Hi there
1965```
1966
1967</figure>
1968
1969-   示例2
1970
1971<figure>
1972
1973```
1974 void vsnprintf_base(char * format, ...)
1975 {
1976     va_list  args;
1977     char  buffer[100];
1978     int iRet =  -1;
1979
1980     va_start(args,  format);
1981     iRet = vsnprintf_s(buffer,  100, 20, format, args);
1982     printf("iRet = %d, buffer  = %s.\n", iRet, buffer);
1983
1984     return;
1985 }
1986 void vsnprintf_sample(void)
1987 {
1988     char    *string = "computer";
1989     wchar_t *wstring =  L"Unicode";
1990
1991     /* format strings.  */
1992     vsnprintf_base("%s,%ls",  string, wstring);
1993
1994     /* test  edge.*/
1995     printf("------------------\n");
1996     vsnprintf_base("%s",  "12345678901234567890a");
1997
1998     return;
1999 }
2000
2001 int main()
2002 {
2003     vsnprintf_sample();
2004     return  0;
2005 }
2006
2007运行结果:
2008iRet = 16, buffer = computer,Unicode.
2009iRet = -1, buffer = 12345678901234567890.
2010```
2011
2012</figure>
2013
2014