最佳做法循环移位(旋转)用C ++操作 [英] Best practices for circular shift (rotate) operations in C++
问题描述
左,右移位运算符(LT;<和>>)都已经用C ++的。
但是,我找不到了,我怎么能进行循环移位或循环操作。
Left and right shift operators (<< and >>) are already available in C++. However, I couldn't find out how I could perform circular shift or rotate operations.
如何能像向左旋转和向右旋转操作来执行?
How can operations like "Rotate Left" and "Rotate Right" be performed?
右旋转两次在这里
Initial --> 1000 0011 0100 0010
应导致:
Final --> 1010 0000 1101 0000
一个例子将是有益的。
An example would be helpful.
(编者注:前pressing的许多常见的方式使用C旋转的未定义行为遭受如果旋转计数为零,或者编译不仅仅是一个单一的旋转机器指令多这个问题的答案应该记录的最佳实践。 )
(editor's note: Many common ways of expressing rotates in C suffer from undefined behaviour if the rotate count is zero, or compile to more than just a single rotate machine instruction. This question's answer should document best practices.)
推荐答案
请参见这个答案对另一个旋转问题全部细节。
最编译器友好的方式前preSS在C旋转,避免任何未定义行为似乎是约翰Regehr 的实施:
The most compiler-friendly way to express a rotate in C that avoids any Undefined Behaviour seems to be John Regehr's implementation:
#include <stdint.h> // for uint32_t
#include <limits.h> // for CHAR_BIT
// #define NDEBUG
#include <assert.h>
uint32_t rotl32 (uint32_t n, unsigned int c)
{
const unsigned int mask = (CHAR_BIT*sizeof(n)-1);
assert ( (c<=mask) &&"rotate by type width or more");
c &= mask; // avoid undef behaviour with NDEBUG. 0 overhead for most types / compilers
return (n<<c) | (n>>( (-c)&mask ));
}
uint32_t rotr32 (uint32_t n, unsigned int c)
{
const unsigned int mask = (CHAR_BIT*sizeof(n)-1);
assert ( (c<=mask) &&"rotate by type width or more");
c &= mask; // avoid undef behaviour with NDEBUG. 0 overhead for most types / compilers
return (n>>c) | (n<<( (-c)&mask ));
}
适用于任何无符号整型,而不仅仅是 uint32_t的
,所以你可以做其他尺寸的版本。这个版本内联到一个 ROL%CL,章
(或 ROL $的imm8,章
)在x86,因为编译器知道该指令已经面具操作内置。
Works for any unsigned integer type, not just uint32_t
, so you could make versions for other sizes. This version inlines to a single rol %cl, reg
(or rol $imm8, reg
) on x86, because the compiler knows that the instruction already has the mask operation built-in.
我不推荐这种模板化的操作数类型,除了私营实施不同宽度的功能。你不想意外地做一个32位的旋转,当你不得不存储在 INT
临时一个16位值。特别是因为整数提升规则可以打开一个前pression涉及窄无符号类型到结果的 INT
。
I would recommend against templating this on the operand type, except as the private implementation for functions with different widths. You don't want to accidentally do a 32bit rotate when you had a 16bit value stored in an int
temporary. Especially since integer-promotion rules can turn the result of an expression involving a narrow unsigned type into an int
.
请确保您使用的无符号的类型 N
和返回值,否则它不会是一个旋转。 (x86上的GCC做算术右移,在符号位,而不是零拷贝转移,导致一个问题,当你或
这两个转移值在一起。右移负符号整数是在C实现定义。)
Make sure you use unsigned types for n
and the return value, or else it won't be a rotate. (gcc on x86 does arithmetic right shifts, shifting in copies of the sign-bit rather than zeroes, leading to a problem when you OR
the two shifted values together. Right-shifts of negative signed integers is implementation-defined behaviour in C.)
(老版这个答案的建议MSVC特有的内联汇编(仅适用于32位的x86 code),或的 http://www.devx.com/tips/Tip/14043 的C版本。这些评论回答了。)
(The old version of this answer suggested MSVC-specific inline asm (which only works for 32bit x86 code), or http://www.devx.com/tips/Tip/14043 for a C version. The comments are replying to that.)
我相信一些编译器提供旋转内部函数,所以这是另一个不可移植的选项,如果这个版本不产生对你打靶编译好的code。
I believe some compilers provide intrinsics for rotates, so that's another non-portable option if this version doesn't generate good code on the compiler you're targetting.
这篇关于最佳做法循环移位(旋转)用C ++操作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!