由于某种原因,我想手动滚动malloc()
的归零版本。为了最大限度地减少算法的复杂性,我想写一下:
void * my_calloc(size_t size)
{
return memset(malloc(size), 0, size);
}
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();
}
答案 0 :(得分:9)
这是glibc声明:
extern void *memset (void *__s, int __c, size_t __n) __THROW __nonnull ((1));
__nonnull
表明它希望指针为非空。
答案 1 :(得分:6)
修改重新:
我后来添加了这个:假设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 memset
和朋友的C标准。
答案 2 :(得分:4)
以下是C99标准对此的说法:
7.1.4“库函数的使用
如果函数的参数具有无效值(例如函数域外的值,或程序地址空间外的指针,或空指针,或指向不可修改存储的指针)相应的参数不是const限定的)或具有可变数量参数的函数不期望的类型(提升后),行为是未定义的。
7.21.1“字符串函数约定”(请记住memset()
位于string.h
)
如果声明为size_t n的参数指定了函数数组的长度,则在调用该函数时,n的值可以为零。除非在本子条款中对特定函数的描述中另有明确说明,否则此类调用上的指针参数仍应具有有效值,如7.1.4中所述。
7.21.6.1“memset函数”
memset函数将c的值(转换为unsigned char)复制到s指向的对象的前n个字符中。
严格来说,由于标准指定s
必须指向一个对象,因此传入空指针将是UB。添加支票(与malloc()
相比的成本将会非常小)。另一方面,如果你知道malloc()
不能失败(因为你有一个终止的自定义),那么显然你不需要在调用memset()
之前进行检查。