c++ - 在 C/C++ 中重置/环绕变量(ringBuffer 指针)
问题描述
我正在编写一些环形缓冲区,这个问题来了好几次。
假设我们有一个计数器,我们需要在一定计数后重置。我见过几个环形缓冲区的例子(主要是音频,环绕 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;
}
}
如果您查看生成的程序集(例如使用Compiler Explorer),您会注意到现代优化编译器如何利用as-if 规则。
Clang (with -O2
) 为这两个函数生成相同的机器代码。它用
xor eax, eax
将零加载到寄存器中,然后
cmove ecx, eax
在需要时“重置”另一个寄存器。
Gcc 只是创建f()
然后g()
变成
jmp f(int)
那说
有什么偏好吗?
一个共同的指导方针是编写更具可读性和可维护性的代码,并仅在对其进行分析后探索可能的优化。
在大多数情况下,我会使用该x = 0;
版本,因为它更好地传达了意图,恕我直言。我只能想到几个原因来采用x -= x;
一个:
- 它不依赖于“幻数”。但是,
42
我的片段中的文字就是这种情况,0
是一个例外情况。 - 它不需要任何隐式转换。考虑任何
x
不是int
. - 可能有一些架构/工具链实际上可以提供更快的代码。我想不出来,但这无关紧要。
推荐阅读
- python - 炮兵 - script.scenarios.forEach 不是函数
- python-3.x - 从 MixedLM 模型中获取最小均方
- reactjs - 无法从 redux 存储中的 reducer 读取属性
- python - 将 django 模型查询集保存到另一个模型中
- amazon-web-services - 如何在不更改上次修改时间的情况下触发 AWS s3 事件?
- c - 相同的输入数据可以有不同的CRC值吗?
- mysql - 如何在 SQL 中反转所有用户交易以获取上一个日期的余额
- git - git log --cherry-pick A..B - 我做错了什么?
- xml - xQuery 使用命名空间的数据?
- javascript - 如何在不同的页面中获取 cookie?