重置/包装 C/C++ 中的变量(环缓冲区指针)

Reseting/wraping around a variable in C/C++ (ringBuffer Pointer)

本文关键字:缓冲区 指针 变量 包装 C++ 重置      更新时间:2023-10-16

我正在编程一些环形缓冲区,这个问题多次出现在我面前。

假设我们有一个计数器,我们需要在一定计数后重置。 我看到了几个环形缓冲区的例子(主要是音频,环绕 r/w 指针),它们这样做:

x++;
if (x  == SOME_NUMBER ){ // Reseting counter
x -= x;
}

这样做有什么区别/偏好吗:

x++;
if (x  == SOME_NUMBER ){ // Reseting counter
x = 0;
}

这个问题几乎适用于所有类型的变量重置。就我而言,除了环形浮子之外,我还重置了一个做平均值的计数器,所以在我做了所有措施后,我重置了那个计数器。

除了结果可能相同(x 重置为零)这一事实之外,一种方法和另一种方法之间可能存在一些差异。有什么偏好吗?

考虑那些稍微修改过的片段版本

void f(int n)
{
int x = 0;
for (;;)
{
++x;
if (x == n ) {   // Reseting counter
x -= x;
}
// Ending condition to avoid UB
if ( x == 42 )
return;
}
}
void g(int n)
{
int x = 0;
for (;;)
{
++x;
if (x == n ) {
x = 0;
}
if ( x == 42 )
return;
}
}

如果您查看生成的程序集(例如,使用编译器资源管理器),您会注意到现代优化编译器如何利用 as-if 规则。

Clang(带-O2)为这两个函数生成相同的机器代码。它使用

xor     eax, eax

将零加载到寄存器中,然后

cmove   ecx, eax

在需要时"重置"另一个寄存器。

gcc 只是创建f()然后g()成为

jmp     f(int)

可是

有什么偏好吗?

一个常见的准则是编写更具可读性和可维护性的代码,并仅在对其进行分析后探索可能的优化。

在大多数情况下,我会使用x = 0;版本,因为它可以更好地传达意图,恕我直言。我只能想到采用x -= x;几个理由:

  • 它不依赖于"幻数"。但是,我的片段中的42文字就是这种情况,0是一个例外情况。
  • 它不需要任何隐式转换。考虑任何x不是int的情况。
  • 可能有一些架构/工具链实际上提供了更快的代码。我想不出任何,但这无关紧要。

区别在于操作的数量:x -= x是减法和赋值,而x = 0只是赋值。除了 CPU 周期数之外,如果可从其他线程访问x,这会影响行为。

一个简单的分配x = 0也更清晰,IMO也是如此。