Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/68.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C+中循环移位(旋转)操作的最佳实践+; 左右移位运算符(>)已经在C++中可用。 但是,我无法找到如何执行循环移位或旋转操作_C++_C_Rotation_Bit Manipulation_C++ Faq - Fatal编程技术网

C+中循环移位(旋转)操作的最佳实践+; 左右移位运算符(>)已经在C++中可用。 但是,我无法找到如何执行循环移位或旋转操作

C+中循环移位(旋转)操作的最佳实践+; 左右移位运算符(>)已经在C++中可用。 但是,我无法找到如何执行循环移位或旋转操作,c++,c,rotation,bit-manipulation,c++-faq,C++,C,Rotation,Bit Manipulation,C++ Faq,如何执行“向左旋转”和“向右旋转”等操作 在这里旋转两次 Initial --> 1000 0011 0100 0010 应导致: Final --> 1010 0000 1101 0000 举个例子会很有帮助 (编者按:如果旋转计数为零,或者编译为一条以上的旋转机器指令,那么C中许多常用的旋转表示方法都会出现未定义的行为。这个问题的答案应该记录最佳实践。)另请参阅的早期版本,了解asm gcc/clang为x86提供的产品的更多详细信息 最简单的编译器友好方式来表达C和C+

如何执行“向左旋转”和“向右旋转”等操作

在这里旋转两次

Initial --> 1000 0011 0100 0010
应导致:

Final   --> 1010 0000 1101 0000
举个例子会很有帮助


(编者按:如果旋转计数为零,或者编译为一条以上的旋转机器指令,那么C中许多常用的旋转表示方法都会出现未定义的行为。这个问题的答案应该记录最佳实践。)

另请参阅的早期版本,了解asm gcc/clang为x86提供的产品的更多详细信息

最简单的编译器友好方式来表达C和C++中的旋转,避免了任何未定义的行为。我已经将其调整为按类型的宽度旋转(使用固定宽度的类型,如

uint32\u t

可能一些非x86编译器也有内部函数,但我们不要扩展这个社区wiki答案来包含它们。(也许在家里可以这样做)


(此答案的旧版本建议使用MSVC特定的内联asm(仅适用于32位x86代码)或C版本。评论正在对此进行回复。)


内联asm击败了许多优化。仔细编写的GNU C内联asm rotate将允许计数成为编译时常量移位计数的立即操作数,但如果内联后要移位的值也是编译时常量,它仍然无法完全优化<强> .< /P> < P>,因为它是C++,使用内联函数:

template <typename INT> 
INT rol(INT val) {
    return (val << 1) | (val >> (sizeof(INT)*CHAR_BIT-1));
}
unsigned int rotate_right(unsigned int x)
{
 return (x>>1 | (x&1?0x80000000:0))
}

unsigned short rotate_right(unsigned short x) { /* etc. */ }
模板
内部rol(内部val){
返回值(val>(sizeof(INT)*字符位1));
}
C++11变体:

template <typename INT> 
constexpr INT rol(INT val) {
    static_assert(std::is_unsigned<INT>::value,
                  "Rotate Left only makes sense for unsigned types");
    return (val << 1) | (val >> (sizeof(INT)*CHAR_BIT-1));
}
模板
constexpr INT rol(INT val){
静态断言(std::is_unsigned::value,
“向左旋转仅适用于无符号类型”);
返回值(val>(sizeof(INT)*字符位1));
}

假设您想右移
L
位,并且输入的
x
是一个带有
N
位的数字:

unsigned ror(unsigned x, int L, int N) 
{
    unsigned lsbs = x & ((1 << L) - 1);
    return (x >> L) | (lsbs << (N-L));
}
unsigned ror(unsigned x,int L,int N)
{
无符号lsbs=x&(1>L)|(lsbs重载函数:

template <typename INT> 
INT rol(INT val) {
    return (val << 1) | (val >> (sizeof(INT)*CHAR_BIT-1));
}
unsigned int rotate_right(unsigned int x)
{
 return (x>>1 | (x&1?0x80000000:0))
}

unsigned short rotate_right(unsigned short x) { /* etc. */ }

大多数编译器都有这方面的内部函数。
例如Visual Studio

如何使用标准位集处理类似的内容

#include <bitset> 
#include <iostream> 

template <std::size_t N> 
inline void 
rotate(std::bitset<N>& b, unsigned m) 
{ 
   b = b << m | b >> (N-m); 
} 

int main() 
{ 
   std::bitset<8> b(15); 
   std::cout << b << '\n'; 
   rotate(b, 2); 
   std::cout << b << '\n'; 

   return 0;
}
#包括
#包括
模板
内联空隙
旋转(标准::位集&b,无符号m)
{ 
b=b>(N-m);
} 
int main()
{ 
std::位集b(15);

std::cout在详细信息中,您可以应用以下逻辑

如果位模式为整数中的33602

1000 0011 0100 0010 1000 0011 0100 0010 您需要使用2个右换档杆进行翻滚,然后: 首先复制位模式,然后将其左移:长度-右移 i、 e.长度为16,右移值为2 16-2=14

在左移14次后,您将获得

1000 0000 0000 0000 1000 0000 0000 0000 现在右移值33602,根据需要移动2次。 你得到

0010 0000 1101 0000 现在取14倍左移值和2倍右移值之间的OR

1000 0000 0000 0000 0010 0000 1101 0000 =================== 1010 0000 1101 0000 =================== 1000 0000 0000 0000 0010 0000 1101 0000 =================== 1010 0000 1101 0000 ===================
然后得到移位的滚动值。记住按位操作更快,甚至不需要任何循环。

如果x是8位值,则可以使用:

x=(x>>1 | x<<7);
x=(x>>1 | x最终:

template<class T>
T ror(T x, unsigned int moves)
{
  return (x >> moves) | (x << sizeof(T)*8 - moves);
}
模板
T ror(T x,无符号整数移动)
{
返回(x>>移动)|(x源代码
x位数字

int x =8;
data =15; //input
unsigned char tmp;
for(int i =0;i<x;i++)
{
printf("Data & 1    %d\n",data&1);
printf("Data Shifted value %d\n",data>>1^(data&1)<<(x-1));
tmp = data>>1|(data&1)<<(x-1);
data = tmp;  
}
intx=8;
data=15;//输入
无符号字符tmp;
对于(int i=0;i>1^(data&1)1 |(data&1)另一个建议

template<class T>
inline T rotl(T x, unsigned char moves){
    unsigned char temp;
    __asm{
        mov temp, CL
        mov CL, moves
        rol x, CL
        mov CL, temp
    };
    return x;
}
模板
内联T旋转(T x,无符号字符移动){
无符号字符温度;
__asm{
移动温度
移动,移动
rol x,CL
温度
};
返回x;
}

正确答案如下:

#define BitsCount( val ) ( sizeof( val ) * CHAR_BIT )
#define Shift( val, steps ) ( steps % BitsCount( val ) )
#define ROL( val, steps ) ( ( val << Shift( val, steps ) ) | ( val >> ( BitsCount( val ) - Shift( val, steps ) ) ) )
#define ROR( val, steps ) ( ( val >> Shift( val, steps ) ) | ( val << ( BitsCount( val ) - Shift( val, steps ) ) ) )
#定义比特流(val)(sizeof(val)*字符位)
#定义班次(val,步骤)(步骤%BITSCONT(val))
#定义ROL(val,步骤)((val>(BitScont(val)-Shift(val,步骤)))

#定义ROR(val,steps)((val>>Shift(val,steps))|(val下面是的一个稍微改进的版本,实现了两个方向,并演示了这些函数使用无符号字符和无符号长值的用法。注意:

  • 这些函数是为编译器优化而内联的
  • 我使用了
    cout(TBitCount-shiftNum));
    }
    模板
    内联T rotateAndCarryRight(T rotateMe,无符号字符移位)
    {
    静态常量无符号字符TBitCount=sizeof(T)*8U;
    return(rotateMe>>shiftNum)|(rotateMe
    ——用8051 C中的RLC代替速度——向左旋转进位
    以下是使用RLC首先更新串行8位DAC msb的示例:
    (r=DACVAL,P1.4=SDO,P1.5=SCLK)
    莫夫A,r
    ?1:
    电影B#8
    RLC A
    MOV P1.4,C
    CLR P1.5
    挫折P1.5
    DJNZ B,?1
    以下是8051 C中最快的代码:
    sbit ACC_7=ACC^7;//在顶部定义此项以访问ACC的第7位
    ACC=r;
    B=8;
    做{
    P1_4=ACC_7;//这将组装成mov c,ACC.7 mov P1.4,c
    
    ACCC++20
    std::rotl
    std::rotr

    它已到达!应将其添加到
    标题中

    用法如下所示:

    #include <bit>
    #include <bitset>
    #include <cstdint>
    #include <iostream>
    
    int main()
    {
        std::uint8_t i = 0b00011101;
        std::cout << "i          = " << std::bitset<8>(i) << '\n';
        std::cout << "rotl(i,0)  = " << std::bitset<8>(std::rotl(i,0)) << '\n';
        std::cout << "rotl(i,1)  = " << std::bitset<8>(std::rotl(i,1)) << '\n';
        std::cout << "rotl(i,4)  = " << std::bitset<8>(std::rotl(i,4)) << '\n';
        std::cout << "rotl(i,9)  = " << std::bitset<8>(std::rotl(i,9)) << '\n';
        std::cout << "rotl(i,-1) = " << std::bitset<8>(std::rotl(i,-1)) << '\n';
    }
    
    当对GCC的支持到达时,我会尝试一下,带有
    g++-9-std=c++2a的GCC 9.1.0仍然不支持它

    提案说:

    标题:

    namespace std {
      // 25.5.5, rotating   
      template<class T>
        [[nodiscard]] constexpr T rotl(T x, int s) noexcept;
      template<class T>
        [[nodiscard]] constexpr T rotr(T x, int s) noexcept;
    
    约束条件:T是无符号整数类型(3.9.1[basic.basical])。 设r为s%N


    返回:如果r为0,x;如果r为正,
    (x>>r)|(x)您应该将x括在括号中,以避免表达式作为宏参数时出现令人不快的意外情况。如果值不是16位,则如果将其定义为宏,则需要小心避免将带有副作用的表达式作为参数传递
    
    #include <iostream>
    
    using namespace std;
    
    template <typename T>
    inline T rotateAndCarryLeft(T rotateMe, unsigned char shiftNum)
    {
        static const unsigned char TBitCount = sizeof(T) * 8U;
    
        return (rotateMe << shiftNum) | (rotateMe >> (TBitCount - shiftNum));
    }
    
    template <typename T>
    inline T rotateAndCarryRight(T rotateMe, unsigned char shiftNum)
    {
        static const unsigned char TBitCount = sizeof(T) * 8U;
    
        return (rotateMe >> shiftNum) | (rotateMe << (TBitCount - shiftNum));
    }
    
    void main()
    {
        //00010100 == (unsigned char)20U
        //00000101 == (unsigned char)5U == rotateAndCarryLeft(20U, 6U)
        //01010000 == (unsigned char)80U == rotateAndCarryRight(20U, 6U)
    
        cout << "unsigned char " << 20U << " rotated left by 6 bits == " << +rotateAndCarryLeft<unsigned char>(20U, 6U) << "\n";
        cout << "unsigned char " << 20U << " rotated right by 6 bits == " << +rotateAndCarryRight<unsigned char>(20U, 6U) << "\n";
    
        cout << "\n";
    
    
        for (unsigned char shiftNum = 0U; shiftNum <= sizeof(unsigned char) * 8U; ++shiftNum)
        {
            cout << "unsigned char " << 21U << " rotated left by " << +shiftNum << " bit(s) == " << +rotateAndCarryLeft<unsigned char>(21U, shiftNum) << "\n";
        }
    
        cout << "\n";
    
        for (unsigned char shiftNum = 0U; shiftNum <= sizeof(unsigned char) * 8U; ++shiftNum)
        {
            cout << "unsigned char " << 21U << " rotated right by " << +shiftNum << " bit(s) == " << +rotateAndCarryRight<unsigned char>(21U, shiftNum) << "\n";
        }
    
    
        cout << "\n";
    
        for (unsigned char shiftNum = 0U; shiftNum <= sizeof(unsigned long long) * 8U; ++shiftNum)
        {
            cout << "unsigned long long " << 3457347ULL << " rotated left by " << +shiftNum << " bit(s) == " << rotateAndCarryLeft<unsigned long long>(3457347ULL, shiftNum) << "\n";
        }
    
        cout << "\n";
    
        for (unsigned char shiftNum = 0U; shiftNum <= sizeof(unsigned long long) * 8U; ++shiftNum)
        {
            cout << "unsigned long long " << 3457347ULL << " rotated right by " << +shiftNum << " bit(s) == " << rotateAndCarryRight<unsigned long long>(3457347ULL, shiftNum) << "\n";
        }
    
        cout << "\n\n";
        system("pause");
    }
    
    --- Substituting RLC in 8051 C for speed --- Rotate left carry
    Here is an example using RLC to update a serial 8 bit DAC msb first:
                                   (r=DACVAL, P1.4= SDO, P1.5= SCLK)
    MOV     A, r
    ?1:
    MOV     B, #8
    RLC     A
    MOV     P1.4, C
    CLR     P1.5
    SETB    P1.5
    DJNZ    B, ?1
    
    Here is the code in 8051 C at its fastest:
    sbit ACC_7  = ACC ^ 7 ; //define this at the top to access bit 7 of ACC
    ACC     =   r;
    B       =   8;  
    do  {
    P1_4    =   ACC_7;  // this assembles into mov c, acc.7  mov P1.4, c 
    ACC     <<= 1;
    P1_5    =   0;
    P1_5    =   1;
    B       --  ; 
        } while ( B!=0 );
    The keil compiler will use DJNZ when a loop is written this way.
    I am cheating here by using registers ACC and B in c code.
    If you cannot cheat then substitute with:
    P1_4    =   ( r & 128 ) ? 1 : 0 ;
    r     <<=   1;
    This only takes a few extra instructions.
    Also, changing B for a local var char n is the same.
    Keil does rotate ACC left by ADD A, ACC which is the same as multiply 2.
    It only takes one extra opcode i think.
    Keeping code entirely in C keeps things simpler sometimes.
    
    #include <bit>
    #include <bitset>
    #include <cstdint>
    #include <iostream>
    
    int main()
    {
        std::uint8_t i = 0b00011101;
        std::cout << "i          = " << std::bitset<8>(i) << '\n';
        std::cout << "rotl(i,0)  = " << std::bitset<8>(std::rotl(i,0)) << '\n';
        std::cout << "rotl(i,1)  = " << std::bitset<8>(std::rotl(i,1)) << '\n';
        std::cout << "rotl(i,4)  = " << std::bitset<8>(std::rotl(i,4)) << '\n';
        std::cout << "rotl(i,9)  = " << std::bitset<8>(std::rotl(i,9)) << '\n';
        std::cout << "rotl(i,-1) = " << std::bitset<8>(std::rotl(i,-1)) << '\n';
    }
    
    i          = 00011101
    rotl(i,0)  = 00011101
    rotl(i,1)  = 00111010
    rotl(i,4)  = 11010001
    rotl(i,9)  = 00111010
    rotl(i,-1) = 10001110
    
    namespace std {
      // 25.5.5, rotating   
      template<class T>
        [[nodiscard]] constexpr T rotl(T x, int s) noexcept;
      template<class T>
        [[nodiscard]] constexpr T rotr(T x, int s) noexcept;
    
    template<class T>
      [[nodiscard]] constexpr T rotl(T x, int s) noexcept;
    
    template<class T>
      [[nodiscard]] constexpr T rotr(T x, int s) noexcept;