1. 执行步骤分解
cpp
unsigned char led_pattern = 0xFE; // 二进制: 1111 1110
// 第一步:计算 (led_pattern << 1)
// 第二步:计算 (led_pattern >> 7)
// 第三步:将两个结果进行 | (按位或) 运算
// 第四步:将最终结果赋值给 led_pattern
2. 具体数值演算
以 led_pattern = 0xFE (1111 1110) 为例:
cpp
步骤1: led_pattern << 1
1111 1110 << 1 = 1111 1100
// 注意:最高位的1移出,最低位补0
步骤2: led_pattern >> 7
1111 1110 >> 7 = 0000 0001
// 右移7位,最低位的0移出,高位补0
// 原最低位的0被丢弃,原来第7位(最高位)的1移到最低位
步骤3: (步骤1的结果) | (步骤2的结果)
1111 1100 (来自步骤1)
0000 0001 (来自步骤2)
---------- |
1111 1101 // 最终结果
步骤4: led_pattern = 1111 1101 (0xFD)
3. 完整8次循环演算表
| 循环次数 | 原值(二进制) | <<1结果 | >>7结果 | OR结果 | 新值(十六进制) | 点亮位置 |
|---|---|---|---|---|---|---|
| 初始 | 1111 1110 |
1111 1100 |
0000 0001 |
1111 1101 |
0xFD | LED1 |
| 1次 | 1111 1101 |
1111 1010 |
0000 0001 |
1111 1011 |
0xFB | LED2 |
| 2次 | 1111 1011 |
1111 0110 |
0000 0001 |
1111 0111 |
0xF7 | LED3 |
| 3次 | 1111 0111 |
1110 1110 |
0000 0001 |
1110 1111 |
0xEF | LED4 |
| 4次 | 1110 1111 |
1101 1110 |
0000 0001 |
1101 1111 |
0xDF | LED5 |
| 5次 | 1101 1111 |
1011 1110 |
0000 0001 |
1011 1111 |
0xBF | LED6 |
| 6次 | 1011 1111 |
0111 1110 |
0000 0001 |
0111 1111 |
0x7F | LED7 |
| 7次 | 0111 1111 |
1111 1110 |
0000 0000 |
1111 1110 |
0xFE | LED0 |
| 8次 | 1111 1110 |
回到初始值,循环重复 | - | - | - | - |
4. 运算优先级说明
C语言中运算符优先级(从高到低):
cpp
1. 括号 () // 最高优先级
2. 移位 << >> // 优先级较高
3. 按位与 & // 中等
4. 按位异或 ^ // 中等
5. 按位或 | // 较低
6. 赋值 = // 最低优先级
// 因此原表达式等价于:
led_pattern = ((led_pattern << 1) | (led_pattern >> 7));
5. 为什么这样写能实现循环左移?
cpp
// 以 8位为例,原始数据 bits[7..0]
// 循环左移1位的结果 = bits[6..0] + bits[7]
// led_pattern << 1 : 得到 bits[6..0] + 0
// led_pattern >> 7 : 得到 0...0 + bits[7]
// 两者 OR 合并 : 得到 bits[6..0] + bits[7]
// 这就是循环左移(ROL)的效果!
6. 等效的汇编指令
您原来的汇编代码:
cpp
ROL AL, 1 ; 循环左移1位
7. 验证代码(可测试执行过程)
cpp
#include <stdio.h>
int main() {
unsigned char led_pattern = 0xFE;
for(int cycle = 0; cycle < 10; cycle++) {
printf("循环%2d: 0x%02X = ", cycle, led_pattern);
// 显示二进制
for(int bit = 7; bit >= 0; bit--) {
printf("%d", (led_pattern >> bit) & 1);
}
// 执行循环左移
led_pattern = (led_pattern << 1) | (led_pattern >> 7);
printf(" -> 0x%02X\n", led_pattern);
}
return 0;
}
输出结果:
bash
循环 0: 0xFE = 11111110 -> 0xFD
循环 1: 0xFD = 11111101 -> 0xFB
循环 2: 0xFB = 11111011 -> 0xF7
循环 3: 0xF7 = 11110111 -> 0xEF
循环 4: 0xEF = 11101111 -> 0xDF
循环 5: 0xDF = 11011111 -> 0xBF
循环 6: 0xBF = 10111111 -> 0x7F
循环 7: 0x7F = 01111111 -> 0xFE
循环 8: 0xFE = 11111110 -> 0xFD
关键要点总结
-
先计算两边的移位表达式(互不影响,都使用原值)
-
再进行按位或运算
-
最后赋值给左侧变量
-
由于是
unsigned char类型,移位超出8位的部分会被丢弃 -
整个过程实现了汇编
ROL指令的功能