直接回答问题
我喜欢罗伯特的回答,但对提出的问题也有一些看法。
总体而言,我对第1部分“边界检查接口”并不信服。第2部分“动态分配功能”草案中的材料更好。
如果要由我决定,我将按照第1部分的内容进行一些操作,但是我还修改了C99标准C库中的接口,这些接口将a返回char *
到字符串的开头(例如strcpy()
and strcat()
),以便代替返回指向起点的指针,他们将返回指向新字符串末尾的空字节的指针。这将使某些常见的习惯用法(例如,将字符串重复连接到另一个字符串的末尾)更加有效,因为避免重复使用的代码所表现出的二次行为将变得微不足道strcat()
。像TR24731版本一样,所有替换都将确保输出字符串的空终止。我并不完全反对检查接口,也不反对异常处理功能。这是一件棘手的事情。
Microsoft的实现与标准规范不同
更新(2011-05-08)
另请参阅此问题。可悲的是,对于TR24731函数的实用性来说,这是致命的,对于Microsoft实现和标准而言,某些函数的定义有所不同,这使它们对我而言毫无用处。我在那儿的答案引用了vsnprintf_s()
。
例如,TR 24731-1说到的接口vsnprintf_s()
是:
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdarg.h>
#include <stdio.h>
int vsnprintf_s(char * restrict s, rsize_t n,
const char * restrict format, va_list arg);
不幸的是,MSDN说到的接口vsnprintf_s()
是:
int vsnprintf_s(
char *buffer,
size_t sizeOfBuffer,
size_t count,
const char *format,
va_list argptr
);
参量
- 缓冲区-输出的存储位置。
- sizeOfBuffer-输出缓冲区的大小。
- count-要写入的最大字符数(不包括终止null)或_TRUNCATE。
- format-格式规范。
- argptr-指向参数列表的指针。
请注意,这不仅仅是类型映射的问题:固定参数的数量是不同的,因此是不可调和的。对我来说(也可能对标准委员会来说)也不清楚,同时拥有“ sizeOfBuffer”和“ count”有什么好处;它看起来像是两次相同的信息(或者,至少,对于两个参数,代码通常将以相同的值编写)。
同样,scanf_s()
其亲属也存在问题。 微软表示,缓冲区长度参数的类型为unsigned
(明确指出“大小参数的类型为unsigned
,不是size_t
”)。相反,在附件K中,size参数的类型为rsize_t
,是size_t
(rsize_t
的另一个名称size_t
,但RSIZE_MAX
小于SIZE_MAX
)的受限变型。因此,同样,scanf_s()
对于Microsoft C和Standard C ,代码调用的编写方式必须不同。
最初,我打算使用“安全”功能作为一种方法,使某些代码可以在Windows和Unix上干净地编译,而无需编写条件代码。由于Microsoft和ISO功能并不总是相同,因此失败了,因此有很多时间要放弃。
Microsoftvsnprintf()
在Visual Studio 2015中的更改
在的Visual Studio 2015文档中vsnprintf()
,它注意到界面已更改:
从Visual Studio 2015和Windows 10中的UCRT开始,vsnprintf
不再与相同_vsnprintf
。该vsnprintf
功能符合C99标准;_vnsprintf
保留是为了向后兼容。
但是,Microsoft的界面vsnprintf_s()
没有更改。
Microsoft与Annex K之间差异的其他示例
C11标准变体localtime_s()
在ISO / IEC 9899:2011附件K.3.8.2.4中定义为:
struct tm *localtime_s(const time_t * restrict timer,
struct tm * restrict result);
与MSDN变体localtime_s()
定义为:
errno_t localtime_s(struct tm* _tm, const time_t *time);
POSIX变体localtime_r()
定义为:
struct tm *localtime_r(const time_t *restrict timer,
struct tm *restrict result);
除了名称,C11标准和POSIX函数是等效的。尽管Microsoft功能与C11标准共享一个名称,但其界面却有所不同。
差异另一个例子是微软的strtok_s()
和附录K的strtok_s()
:
char *strtok_s(char *strToken, const char *strDelimit, char **context);
vs:
char *strtok_s(char * restrict s1, rsize_t * restrict s1max, const char * restrict s2, char ** restrict ptr);
请注意,Microsoft变体具有3个参数,而Annex K变体具有4个参数。这意味着Microsoft的参数列表strtok_s()
与POSIX的参数列表兼容。strtok_r()
-因此,如果您更改函数名称(例如,通过宏),则对它们的调用实际上是可互换的-但标准C(附件K)版本与两者的区别在于额外的参数。
问题Mac和Linux上的不同声明qsort_r()
的答案也qsort_s()
像Microsoft定义的和qsort_s()
TR24731-1定义的那样讨论-再次,接口是不同的。
ISO / IEC 9899:2011-C11标准
C11标准(2010年12月草案;您可以一次从ANSI网站商店以30美元的价格获取权威标准ISO / IEC 9899:2011的PDF副本)中确实包含TR24731-1功能标准的一部分。它们在附件K(边界检查接口)中定义,这是“规范”而非“信息”,但它是可选的。
C11标准中没有TR24731-2功能-这很可悲,因为该vasprintf()
功能及其亲戚可能真的有用。
快速总结:
- C11包含TR24731-1
- C11不包含TR24731-2
- C18与C11 wrt TR24731相同。
关于将附件K从C11的继承人中删除的提案
重复数据删除器在对另一个问题的评论中指出,ISO C标准委员会(ISO / IEC JTC1 / SC22 / WG14)已有一项提案。
它包含对附件K功能的某些现有实现的引用-没有一个被广泛使用(但如果您有兴趣,可以在文档中找到它们)。
该文件以建议结尾:
因此,我们建议将附件K从C标准的下一个修订版本中删除,或者不推荐使用,然后删除。
我支持该建议。
C18标准没有改变附件K的状态。有一篇论文N2336主张对附件K进行一些更改,修复其缺陷而不是完全删除它。
strlen()
到代码”的含义。在某些情况下,肯定会有错误strlen()
的答案,例如,将缓冲区传递给I / O函数(例如gets_s()
)。但是也许您可以详细说明您的想法?