C memmove 相当于 for 循环 - 段错误

C memmove equivalent of for loop - segfault

我正在实施具有动态调整大小的环形缓冲区。当 tail 在 head 后面时,缓冲区末尾的数据必须在调整大小后移动到缓冲区的新末尾。为此,我编写了以下代码:

memmove(self->broadcaster.events+self->broadcaster.events_head+self->broadcaster.events_size,
              self->broadcaster.events+self->broadcaster.events_head,
              self->broadcaster.events_size-self->broadcaster.events_head);

其中 self->broadcaster.events_size 是旧尺寸 (new_size/2)。不幸的是,它会导致分段错误。我认为它等效于此代码:

for (i = 0 ; i < self->broadcaster.events_size - self->broadcaster.events_head ; ++i)
        self->broadcaster.events[self->broadcaster.events_size+self->broadcaster.events_head+i]=
            self->broadcaster.events[self->broadcaster.events_head+i];

但是这种天真的 for 循环实现可以正常工作,所以我似乎不知道如何正确使用 memmove。这两段代码有何不同?

它们只有在 sizeof(*self->broadcaster.events) == 1 时才等价。

为清楚起见,我已将 self->broadcaster 替换为 b,将 events 替换为 e,并在您的代码中添加了一些空格。

memmove(b.e + b.e_head + b.e_size, b.e + b.e_head, b.e_size - b.e_head);

将仅复制 b.e_size - b.e_head 个字节,并且循环:

for (i = 0 ; i < b.e_size - b.e_head ; ++i)
        b.e[b.e_size + b.e_head + i] = b.e[b.e_head + i];

将复制 (b.e_size - b.e_head) * sizeof *b.e 个字节,因为每个 b.e[...] = b.e[...] 赋值移动 sizeof *b.e 个字节,每个 ++ib.e[... + i] 的地址推进sizeof *b.e 字节。

如果你定义一个宏,你会得到最好的服务:

#define MOVE(dst, src, count)  memmove((dst), (src), (count) * sizeof *(src))

并用它代替 memmove

但是你当然可以把memmove的最后一个参数改成

(self->broadcaster.events_size-self->broadcaster.events_head)*sizeof*self->broadcaster.events