出于这样或那样的原因,我想手动滚动归零版本malloc().为了最大限度地减少算法的复杂性,我想写:
void * my_calloc(size_t size)
{
return memset(malloc(size), 0, size);
}
Run Code Online (Sandbox Code Playgroud)
这个定义明确size == 0吗?可以malloc()使用零大小调用,但这允许它返回空指针.请问后续调用memset是否正常,或者这是未定义的行为,我需要添加一个条件if (size)?
我非常想避免多余的条件检查!
假设malloc()暂时没有失败.实际上那里也会有一个手动滚动版本malloc(),它会在失败时终止.
像这样的东西:
void * my_malloc(size_t size)
{
void * const p = malloc(size);
if (p || 0 == size) return p;
terminate();
}
Run Code Online (Sandbox Code Playgroud)
这是glibc声明:
extern void *memset (void *__s, int __c, size_t __n) __THROW __nonnull ((1));
Run Code Online (Sandbox Code Playgroud)
的__nonnull,它期待着指针非空的节目.
以下是 C99 标准对此的说明:
如果函数的参数具有无效值(例如函数域外的值,或程序地址空间外的指针,或空指针,或指向不可修改存储的指针)不是 const 限定的)或具有可变数量参数的函数不期望的类型(升级后),行为未定义。
memset()是在 string.h)如果参数声明为
size_t n指定函数数组的长度,则n在调用该函数时可以具有零值。除非在本小节中对特定函数的描述中另有明确说明,否则此类调用的指针参数仍应具有有效值,如 7.1.4 中所述。
该
memset函数将 的值c(转换为 anunsigned char)复制到n指向的对象的每个第一个字符中s。
所以严格来说,由于标准规定s必须指向一个对象,所以传入一个空指针就是UB。添加支票(与 相比,成本malloc()将小得惊人)。另一方面,如果您知道malloc()不能失败(因为您有一个终止的自定义),那么显然您不需要在调用memset().
编辑 Re:
我后来添加了这个:假设malloc()永远不会失败.问题是只有大小可以为0
我知道了.因此,如果指针为NULL 且大小为0,则只希望事物安全.
参考POSIX文档
不,没有指定使用NULL指针调用memset应该是安全的(如果你用零计数或大小调用它...那就更有趣',但也没有指定).
在"信息"部分甚至没有提及它.
请注意,第一个链接提到
此参考页面上描述的功能与ISO C标准一致.此处描述的要求与ISO C标准之间的任何冲突都是无意的.IEEE Std 1003.1-2001的该卷符合ISO C标准
更新我可以确认ISO C99标准(n1256.pdf)与POSIX文档同样简短,而 C++ 11规范仅涉及ansi C标准memset和朋友.