C语言移位操作遇到的问题和解决办法

article/2025/10/11 2:30:17

        最近在调试一个Camera ISP OTP校准的问题,在开发过程中,要将2个字节的数据组合成16bit的数据。一开始我以为只要是一大块内存,我们告诉它类型,那么编译器就会自动分配对应的内容。例如:下面图1中连续的内容,加入这里我把uint8_t temp[4] = {0x20,0x33,0x44,0x55},现在我想把它放到一个结构类型的数据中,假如这里数据结构是:

struct test{uint16_t   a;uint16_t   b;
}

这里我们有struct test  *arm = (struct test *)test;这样一行代码,大家猜猜arm中对应的a,b域分别是多少。一开始我以为就是arm->a = 0x2033,arm->b = 0x4455;

                                                                                                                                                    

                                                                                            实际存放状态                                                                                             目的状态

      经过实际代码验证,由于存在大小端问题,它会将低地址的数据放到高位,高地址的数据放到低位。如下试验代码

试验代码1

#include<stdio.h>
unsigned char temp[] = {0x20,0x33,0x44,0x55};
struct test{unsigned short a;unsigned short b;
};int main(){struct test * arm = (struct test *)temp;printf("A:0x%x\n",arm->a);printf("B:0x%x\n",arm->b);
}
打印结果:看到结果的瞬间,大家都明白了吧。

A:0x3320
B:0x5544
实验代码2

实验2重要研究移位操作对赋值的影响,如下面代码标识出的。

#include<stdio.h>typedef struct {unsigned short a;unsigned short b;unsigned short c;
}data_test;unsigned char temp[6]={0x11,0x22,0x33,0x44,0x55,0x66};void test(unsigned char *in){data_test dta;unsigned char *in_data = in;dta.a = (*in_data & 0xff) <<8  + (*(in_data+1)&0xff);     //---------------------dta.b = (*(in_data+2) & 0xff) <<8  + (*(in_data+3)&0xff); //---------------------dta.c = (*(in_data+4) & 0xff) <<8  + (*(in_data+5)&0xff); //---------------------printf("armwind,0x%x\n",dta.a);printf("armwind,0x%x\n",dta.b);printf("armwind,0x%x\n",dta.c);int i;for(i=0;i<6;i++){printf("hehe:0x%x\n",*(in_data +i));}
}
int main(){test(temp);printf("char:%d\n",sizeof(unsigned char));printf("short:%d\n",sizeof(unsigned short));
}
运行结果:

armwind,0x4400
armwind,0x3000
armwind,0x4000
hehe:0x11
hehe:0x22
hehe:0x33
hehe:0x44
hehe:0x55
hehe:0x66
char:1
short:2

上面的代码很简单,就是有3行非常不解,字面上看没什么错误,但为什么打出来的结果和我们预期的,有这么大差异呢。为此我将代码反汇编了,在汇编代码中我找到了原因。请看汇编代码片段。

	dta.a = (*in_data & 0xff) <<8  + (*(in_data+1)&0xff);     dta.b = (*(in_data+2) & 0xff) <<8  + (*(in_data+3)&0xff); dta.c = (*(in_data+4) & 0xff) <<8  + (*(in_data+5)&0xff); 
汇编代码片段:

void test(unsigned char *in){4004f4:	55                   	push   %rbp4004f5:	48 89 e5             	mov    %rsp,%rbp4004f8:	53                   	push   %rbx4004f9:	48 83 ec 38          	sub    $0x38,%rsp4004fd:	48 89 7d c8          	mov    %rdi,-0x38(%rbp) //这里申请临时变量堆栈,用来data_test dta;unsigned char *in_data = in;400501:	48 8b 45 c8          	mov    -0x38(%rbp),%rax 400505:	48 89 45 d8          	mov    %rax,-0x28(%rbp) //*in_data = in;dta.a = (*in_data & 0xff) <<8  + (*(in_data+1)&0xff);400509:	48 8b 45 d8          	mov    -0x28(%rbp),%rax     //取到in_data指针40050d:	0f b6 00             	movzbl (%rax),%eax             //拿到*in_data值400510:	0f b6 d0             	movzbl %al,%edx                  //;(*in_data)&0xff  取低8位 --------------------------------------->前面一半计算的结果在edx中。400513:	48 8b 45 d8          	mov    -0x28(%rbp),%rax    //开始(*(in_data+1)&0xff),这是拿到in_data指针。400517:	48 83 c0 01          	add    $0x1,%rax                   //in_data 进行+1操作40051b:	0f b6 00             	movzbl (%rax),%eax             //;(*(in_data +1))40051e:	0f b6 c0             	movzbl %al,%eax                  //(*(in_data+1)&0xff)计算的结果取低8位,放到eax,高位补0.400521:	83 c0 08             	add    $0x8,%eax                   //;这里直接就是将eax+8了,这里可以移位的数量,之前eax存放的是高8位数据------------>这个地方就出现问题了。不应该直接加eax。400524:	89 d3                	mov    %edx,%ebx                //;ebx中存放的是高8位数据。400526:	89 c1                	mov    %eax,%ecx                 //400528:	d3 e3                	shl    %cl,%ebx                      //;高8位数据逻辑左移动cl个寄存器。40052a:	 89 d8                	mov    %ebx,%eax40052c:	66 89 45 e0          	mov    %ax,-0x20(%rbp)dta.b = (*(in_data+2) & 0xff) <<8  + (*(in_data+3)&0xff);400530:	48 8b 45 d8          	mov    -0x28(%rbp),%rax400534:	48 83 c0 02          	add    $0x2,%rax400538:	0f b6 00             	movzbl (%rax),%eax40053b:	0f b6 d0             	movzbl %al,%edx40053e:	48 8b 45 d8          	mov    -0x28(%rbp),%rax400542:	48 83 c0 03          	add    $0x3,%rax 400546:	0f b6 00             	movzbl (%rax),%eax400549:	0f b6 c0             	movzbl %al,%eax40054c:	83 c0 08             	add    $0x8,%eax //同理,这里 (*(in_data+3)&0xff) + 8操作40054f:	89 d3                	mov    %edx,%ebx400551:	89 c1                	mov    %eax,%ecx400553:	d3 e3                	shl    %cl,%ebx400555:	89 d8                	mov    %ebx,%eax400557:	66 89 45 e2          	mov    %ax,-0x1e(%rbp)dta.c = (*(in_data+4) & 0xff) <<8  + (*(in_data+5)&0xff);40055b:	48 8b 45 d8          	mov    -0x28(%rbp),%rax40055f:	48 83 c0 04          	add    $0x4,%rax400563:	0f b6 00             	movzbl (%rax),%eax400566:	0f b6 d0             	movzbl %al,%edx400569:	48 8b 45 d8          	mov    -0x28(%rbp),%rax40056d:	48 83 c0 05          	add    $0x5,%rax400571:	0f b6 00             	movzbl (%rax),%eax400574:	0f b6 c0             	movzbl %al,%eax400577:	83 c0 08             	add    $0x8,%eax //同理,这里 (*(in_data+5)&0xff) + 8操作,这是无效的。40057a:	89 d3                	mov    %edx,%ebx40057c:	89 c1                	mov    %eax,%ecx40057e:	d3 e3                	shl    %cl,%ebx400580:	89 d8                	mov    %ebx,%eax400582:	66 89 45 e4          	mov    %ax,-0x1c(%rbp)
...................
总结:以后在将高八位,低八位进行拼接的时候,最好使用一个中间变量,要不然编译器会直接舍弃调低8位,导致运算失效。切记,切记!!!!


http://chatgpt.dhexx.cn/article/61v2mx7c.shtml

相关文章

逻辑右移、算数右移的区别与C语言移位运算符解析

在学习汇编语言的时候&#xff0c;对于左移、算数右移、逻辑右移一般有不同的指令&#xff0c;这几者之间有什么区别和联系&#xff1f; 逻辑右移和算数右移的区别 右移是将数据逐位向低位移动&#xff0c;最低位丢弃&#xff0c;而根据最高位以0填充还是以原始数据的符号位填充…

C语言实现移位密码

一.认识密码学 加密算法分为对称加密和非对称加密&#xff1a; 对称加密&#xff1a;对称加密算法使用相同的密钥进行加密和解密操作。发送方和接收方需要共享同一个密钥&#xff0c;这个密钥被称为对称密钥。对称加密算法的优势在于加密和解密速度快&#xff0c;适用于大量数…

C语言实现移位密码体制

问题描述&#xff1a;输入密钥K的值&#xff0c;加密算法&#xff1a;e(x)xk(mod 26)。即当前明文字母顺序&#xff08;如A为1&#xff09;加上K值之后对应的字母即为密文。解密算法&#xff1a;d(y)y-k(mod 26)。与加密相反&#xff0c;解密是当前密文字母顺序减去K值对应的字…

c语言中的移位运算符

移位运算符在程序设计中&#xff0c;是位操作运算符的一种。移位运算符可以在二进制的基础上对数字进行平移。 c语言中提供了两种移位运算符&#xff1a; 左移运算符&#xff1a;<< 右移运算符&#xff1a;>> 左移运算符&#xff08;<<&#xff09; int ma…

C语言移位操作、联合体总结

&#xff08;1&#xff09;用|置1&#xff0c;例如P1_flag | 0x01;//置1 0000 0001&#xff0c;把bit0置1&#xff1b; &#xff08;2&#xff09;用&置0&#xff0c;例如P1_flag & 0xFE;//置0 1111 1110&#xff0c;把bit0置0&#xff1b; &#xff08;3&#xff09;把…

C语言——移位操作符

目录 左移操作符 右移操作符 算术右移 逻辑右移 总结 内存中存储的是二进制的补码。 所以移位操作符是对二进制补码进行移位。 先以左移操作符为例:<< 左移操作符 正数的情况&#xff1a; #include<stdio.h> int main() {int a10; //00000000000000000000…

【C语言】超详细的移位、位操作符详解(含力扣实战)

目录 ?1、整数的二进制表示 ?2、移位操作符 ?2.1左移操作符(低位补0) ?举例 ?原理分析 ??2.2右移操作符 ?算术右移(高位补原符号位) ?逻辑右移(高位补0) ??3、位操作符 ?3.1按位与& ?原理分析 ?3.2按位或| ?原理分析 ?3.3按位异或^ ?…

C语言的移位操作

1. C语言的移位 在C语言中&#xff0c;左移为逻辑移位&#xff0c;即左移右侧补0&#xff1b;右移为算术移位&#xff0c;即右移左侧补符号位。 上述程序对 -2 进行左移一位和右移一位的操作&#xff0c;可见-2在内存中存储为ffffffffe即11111111 11111111 11111111 1111 11…

【C语言初阶】操作符之 位运算符详解(“ << ”,“ >> ”,“ ”,“ | ”,“ ^ ”,“ ~ ”)

目录 C语言中六种位运算符&#xff1a; 一、位移运算符 1、移位运算符简介 2、先要了解一点 3、 << 左移运算符 4、>>右移运算符 5、警告 二、 1、& 按位与 2、| 按位或 3、^ 按位异或 4、~ 取反 4、例子 C语言中六种位运算符&#xff1a; &…

C语言中的移位运算

左移运算&#xff1a;对于一个位表示为的操作数 x&#xff0c;x << k 会生成一个指&#xff0c;其位表达式为。也就是说将x右边的w-k位向左移动k位&#xff0c;丢弃最高的k位&#xff0c;并在右端补k个0. 例如&#xff1a;操作数 x 位表达式为 01010101&#xff0c;x &l…

2021 华为秋招笔试题

练习: 题目描述&#xff1a; 学校有一个在线学习系统&#xff0c;没门课程由N个页面组成&#xff08;0< N< 10000&#xff09;个页面组成&#xff0c;学生从第一页开始按顺序学到最后一页提交学习记录。 系统会记录每页停留的时间&#xff08;单位秒&#xff09;&#xf…

详解2021华为笔试三道编程题

目录 2021华为笔试第一道 缓存转发数据包统计&#xff08;100%&#xff09; 解题思路&#xff1a; 参考代码&#xff1a; 2021华为笔试第二题 查找知识图谱中的实例知识&#xff08;100%&#xff09; 解题思路&#xff1a; 参考代码&#xff1a; 2021华为笔试第三题 …

笔试题(2021.7.21华为)

2021.7.21 今晚华为的面试题&#xff0c;帮同学做的&#xff0c;记录一下 说实话还挺难的&#xff0c;基本都算中等题&#xff0c;而且光看题就得看半天 链路可靠性 思路 建图&#xff0c;dfs 我这里是用的哈希表&#xff0c;加数组的形式&#xff0c;也差不多 import java.…

华为笔试AC的两道(第三道不会,我太菜)

1、猪场防疫 老李在多年前承包了一个养猪场&#xff0c; 并引入了若干只种猪&#xff0c;经过这些年的经营&#xff0c;现在养猪场有N只猪&#xff0c;编号从0到N-1 (每只猪无论生死都有唯一的编号) ; 老李在每只猪生产的时候记下了生产的母猪和出生的小猪&#xff0c;格式: x …

2021-07-08 华为2022批笔试

华为2022批笔试 三道题T1T2T3 三道题 总结&#xff1a;写的时候太紧张了&#xff0c;很烦 T1 题目&#xff1a;给出n个任务的最晚完成时间&#xff08;单位为小时&#xff09;和对应积分&#xff0c;每小时只能做一个任务&#xff0c;且超时后不获得积分&#xff0c;求出最大…

2017华为笔试、面试经历

**背景介绍**&#xff1a;2016年7月参加第十一届“华为杯”研究所电子设计大赛获西北赛区一等奖&#xff0c;于2016年8月到上海嘉定工业区参加全国总决赛获全国三等奖。 期间&#xff0c;参加了在线测评、笔试、专业面试、综合面试、部门选择、未完待续。 **备注**&#xff1a;…

4.15日华为笔试

参考&#xff1a; 华为笔试&#xff0c;大家做的怎么样&#xff1f;华为4.15笔试前两题AC - 正则表达式华为笔试2.7 4-15 - C华为4.15笔试 - C 题目简介&#xff1a; 第一题&#xff1a;求获胜者&#xff0c;如果票数相当&#xff0c;按照字母排序&#xff0c;a>b>c,A…

19.华为笔试题整理

1.两数之和 数组可以有重复元素,所以与力扣的第一题稍微有点不同 public int[] twoSum(int[] numbers, int target) {int n numbers.length;HashMap<Integer, Integer> map new HashMap<>();for (int i 0; i < n; i) {int realTarget target - numbers[i];i…

华为2020校招笔试编程题

华为2020校招笔试编程题 刚做完华为的笔试题&#xff0c;简要描述一下三道编程题的解决方法以及python代码实现 第一题大致描述&#xff1a; 给定两个已经升序排序好的的序列A{a1,a2,a3,...an} 和B{b1,b2,b3...bn} &#xff0c;一个数R&#xff0c;找出满足以下条件的的&#x…

华为笔试题 2022.3.30

1、业务部署芯片 思路&#xff0c;就硬模拟 #include <algorithm> #include <iostream> #include <string> #include <vector>using namespace std;int main() {int m, n;cin >> m;cin >> n;char arr[n];for (int i 0; i < n; i) {ci…