【问题标题】:Can I call memcpy() and memmove() with "number of bytes" set to zero?我可以调用 memcpy() 和 memmove() 并将“字节数”设置为零吗?
【发布时间】:2011-04-14 16:29:33
【问题描述】:

当我实际上没有东西可以移动/复制时,我是否需要处理将memmove()/memcpy() 作为边缘情况的情况

int numberOfBytes = ...
if( numberOfBytes != 0 ) {
    memmove( dest, source, numberOfBytes );
}

或者我应该直接调用函数而不检查

int numberOfBytes = ...
memmove( dest, source, numberOfBytes );

前sn-p中的check有必要吗?

【问题讨论】:

  • 这个问题让我想起了一些检查诸如 free 之类的函数的空指针。没有必要,但我会在此处发表评论以表明您对此的想法。
  • @Toad:除了弄乱代码之外,还有什么目的?在阅读某人的代码时,我不需要知道原来的程序员“想过做这个实际上没有必要的操作,但因为它没有必要,所以我没有做”。如果我看到一个指针被释放,我知道它允许为空,所以我不需要知道原始程序员关于“我应该检查是否为空”的想法。使用 memcpy 复制 0 个字节也是如此
  • @jalf:这是一个关于 stackoverflow 的问题,这让人怀疑。因此,添加评论可能对您没有帮助,但可能会对知识较少的人有所帮助
  • @Toad 是的,cmets 明确指出为什么看起来必要的检查实际上没有原则上是有价值的。硬币的另一面是这个特殊的例子是一个常见的案例,涉及一个标准库函数,每个程序员只需要学习一次答案;然后他们可以在他们阅读的任何程序中识别出不需要这些检查。出于那个的原因,我会省略 cmets。像这样具有多个调用的代码库要么需要将 cmets 复制并粘贴到每个调用中,要么仅在某些调用中任意使用它们,这两者都很丑。

标签: c++ c pointers memcpy memmove


【解决方案1】:

来自 C99 标准 (7.21.1/2):

声明为size_t n 的参数指定数组的长度 函数,n 在调用该函数时可以具有零值。除非明确说明 否则,在本小节中对特定函数的描述中,指针参数 如 7.1.4 中所述,在此类调用中仍应具有有效值。在这样的呼叫中, 定位一个字符的函数没有发现任何出现,一个比较两个字符的函数 字符序列返回零,复制字符的函数复制零 字符。

所以答案是否定的;检查是没有必要的(或者是的;你可以通过零)。

【讨论】:

  • 如果指针指向数组最后一个元素之后的位置,是否会被认为是“有效”的函数?这样的指针不能被合法地尊重,但可以安全地做一些其他指针式的事情,比如从中减去一个。
  • @supercat: 是的,指向数组末尾之后的指针对于与该数组内(或末尾之后)的其他指针的指针算术有效,但不可取消引用。
  • @MikeSeymour:引用不应该暗示相反的答案:检查是必要的,你不能用空指针传递零?
  • @neverhoodboy:不,引用清楚地表明“n 的值可以为零”。你是正确的,你不能传递空指针,但这不是问题要问的。
  • @MikeSeymour:我的错。真对不起。问题是关于大小而不是指针。
【解决方案2】:

正如@You 所说,标准规定 memcpy 和 memmove 应该毫无问题地处理这种情况;因为它们通常以某种方式实现,例如

void *memcpy(void *_dst, const void *_src, size_t len)
{
    unsigned char *dst = _dst;
    const unsigned char *src = _src;
    while(len-- > 0)
        *dst++ = *src++;
    return _dst;
}

除了函数调用之外,你甚至不应该有任何性能惩罚;如果编译器支持此类函数的内在函数/内联,则额外的检查甚至可能会使代码变慢一点点,因为此时检查已经完成。

【讨论】:

  • 我认为这个函数可能是在汇编中制作的,在那里你可以比在 c 中更好地优化内存传输
  • "somewhat like" :) 实际上我见过的几乎所有实现都是在汇编中,并尝试使用本机字长复制大部分位(例如 uint32_t在 x86 上),但这不会改变答案的实质:它是一个 while 循环,在开始之前不需要大量计算,因此检查已经完成。
  • -1,典型的实现与用零参数调用这些函数(甚至可能不作为C函数实现)是否是有效的C无关。
  • 它是有效的 C 的事实已经被其他答案所涵盖,正如我在回答一开始所说的那样:“正如@You 所说,标准指定 memcpy 和 memmove 应该毫无问题地处理这种情况”。我只是添加了我的观点,即出于性能原因,您甚至不应该担心使用 len=0 调用 memcpy,因为在这种情况下,它的调用成本几乎为零。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-23
  • 2015-01-13
  • 1970-01-01
  • 1970-01-01
  • 2022-01-10
相关资源
最近更新 更多