C语言 如果内存大小为0,memset()可以带空指针调用吗?



出于这样或那样的原因,我想手工滚动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();
}

下面是glibc声明:

extern void *memset (void *__s, int __c, size_t __n) __THROW __nonnull ((1));

__nonnull显示它期望指针非空

C99标准是这么说的:

7.1.4"库函数的使用"

如果函数的实参有一个无效的值(例如函数域之外的值,或者程序地址空间之外的指针,或者空指针,或者当相应的形参不是const限定时指向不可修改存储的指针),或者具有可变数量实参的函数不期望的类型(在提升之后),则行为是未定义的。

7.21.1 String函数约定;(记住memset()string.h中)

如果声明为size_t n的实参指定了函数的数组长度,则在调用该函数时n的值可以为0。除非在本小节中特定函数的描述中另有明确说明,否则此类调用的指针实参仍应具有有效值,如7.1.4所述。

7.21.6.1"memset函数"

memset函数将c的值(转换为unsigned char)复制到s所指向对象的前一个n字符中。

所以严格来说,由于标准规定s必须指向一个对象,传递一个空指针将是UB。添加检查(与malloc()相比,成本将非常小)。另一方面,如果您知道malloc()不会失败(因为您有一个自定义的终止),那么显然您不需要在调用memset()之前执行检查。

Edit Re:

我后来添加了这一点:假设malloc()永远不会失败。问题是size是否可以为0

我明白了。所以只有当指针为空的大小为0时,你才希望事情是安全的。

引用POSIX文档

  • http://pubs.opengroup.org/onlinepubs/009695399/functions/memset.html
  • http://pubs.opengroup.org/onlinepubs/7908799/xsh/memset.html

没有,没有指定使用空指针调用memset应该是安全的(如果您以零计数或大小调用它…那样会更"有趣",但也没有特别说明)。

在"信息"部分甚至没有提到它。

注意,第一个链接提到了

本参考页描述的功能与ISO C标准保持一致。此处描述的要求与ISO C标准之间的任何冲突都是无意的。本卷IEEE Std 1003.1-2001遵循ISO C标准

更新我可以确认ISO C99标准(n1256.pdf)与POSIX文档一样简短,c++ 11规范只是参考了memset和朋友的ANSI C标准。N1256州:

memset函数将c的值(转换为unsigned char)复制到s所指向对象的前一个n字符中。

并没有说明s为空的情况(但请注意,空指针不指向对象)。

相关内容

  • 没有找到相关文章

最新更新