C语言移位操作遇到的问题和解决办法
来源:互联网 发布:松下网络摄像机软件 编辑:程序博客网 时间:2024/06/14 15:26
最近在调试一个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:0x3320B: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,0x4400armwind,0x3000armwind,0x4000hehe:0x11hehe:0x22hehe:0x33hehe:0x44hehe:0x55hehe:0x66char:1short: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 %rbp 4004f5:48 89 e5 mov %rsp,%rbp 4004f8:53 push %rbx 4004f9:48 83 ec 38 sub $0x38,%rsp 4004fd: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,%eax 40052c: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),%rax 400534:48 83 c0 02 add $0x2,%rax 400538:0f b6 00 movzbl (%rax),%eax 40053b:0f b6 d0 movzbl %al,%edx 40053e:48 8b 45 d8 mov -0x28(%rbp),%rax 400542:48 83 c0 03 add $0x3,%rax 400546:0f b6 00 movzbl (%rax),%eax 400549:0f b6 c0 movzbl %al,%eax 40054c:83 c0 08 add $0x8,%eax //同理,这里 (*(in_data+3)&0xff) + 8操作 40054f:89 d3 mov %edx,%ebx 400551:89 c1 mov %eax,%ecx 400553:d3 e3 shl %cl,%ebx 400555:89 d8 mov %ebx,%eax 400557: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),%rax 40055f:48 83 c0 04 add $0x4,%rax 400563:0f b6 00 movzbl (%rax),%eax 400566:0f b6 d0 movzbl %al,%edx 400569:48 8b 45 d8 mov -0x28(%rbp),%rax 40056d:48 83 c0 05 add $0x5,%rax 400571:0f b6 00 movzbl (%rax),%eax 400574:0f b6 c0 movzbl %al,%eax 400577:83 c0 08 add $0x8,%eax //同理,这里 (*(in_data+5)&0xff) + 8操作,这是无效的。 40057a:89 d3 mov %edx,%ebx 40057c:89 c1 mov %eax,%ecx 40057e:d3 e3 shl %cl,%ebx 400580:89 d8 mov %ebx,%eax 400582:66 89 45 e4 mov %ax,-0x1c(%rbp)...................总结:以后在将高八位,低八位进行拼接的时候,最好使用一个中间变量,要不然编译器会直接舍弃调低8位,导致运算失效。切记,切记!!!!
- C语言移位操作遇到的问题和解决办法
- 关于C语言的文件型指针和移位操作中的一些有趣问题的探讨
- c语言的移位问题
- C语言中的移位操作(逻辑移位和算…
- C语言移位操作
- C语言的移位操作符
- C语言的移位操作符
- C语言的移位操作符
- C语言的移位操作符
- c语言---移位问题
- C语言中的移位操作
- C语言中的移位操作
- C语言中的移位操作
- C语言中的移位操作
- C语言零移位操作
- C语言循环移位操作
- C语言中的移位操作
- C 语言移位操作陷阱
- Java Web项目开发流程
- 跟着鬼哥学爬虫-10-python微信-5-加上了人工智能回复!
- Apache的URL重写规则的标志详细说明
- String-date-Calendar转换,日期的加减格式化操作
- SQL Server 表分区
- C语言移位操作遇到的问题和解决办法
- js获取cookie
- Struts2+spring3+mybatis3整合注解开发
- 版本控制svn-Versions
- 第5章 路由事件(1)——概述
- Delphi FireDAC 出现Variable length column[*] overflow. Value length - [80], column maximum length
- hdu3910 Liang Guo Sha(期望)
- android中利用sharedpreference进行数据存储
- Git分支管理策略