简体   繁体   English

移位不正确?

[英]Bit shifting not shifting correctly?

I am programming the 8051 in C using the Si Labs IDE. 我正在使用Si Labs IDE在C语言中对8051进行编程。 I currently have three bytes: address_byte3, address_byte2, and address_byte1 . 我目前有三个字节: address_byte3, address_byte2, and address_byte1 I then initialized a variable address_sum to be an unsigned long int then did the following operation on it... 然后我将变量address_sum初始化为一个unsigned long int然后对其执行以下操作...

address_sum=(address_byte3<<16)+(address_byte2<<8)+(address_byte1);

This operation would lead me to believe that the value loaded into address_sum if address_byte3, address_byte2, & address_byte1 were 0x92, 0x56, & 0x78 , respectively, would be 0xXX925678 . 该操作使我相信,如果address_byte3, address_byte2, & address_byte1分别为0x92, 0x56, & 0x78 ,则加载到address_sum中的值将为0xXX925678 Instead I am getting a value of 0xXX005678 . 相反,我得到的值为0xXX005678 My logic seems sound but then again I am the one writing the code so I'm biased and could be blinded by my own ignorance. 我的逻辑似乎很合理,但是我又是编写代码的人,所以我有偏见,可能会因自己的无知而蒙蔽双眼。 Does anyone have a solution or an explanation as to why the value for address_byte is "lost"? 是否有人对为什么address_byte的值“丢失”有解决方案或解释?

Thank you. 谢谢。

Variables shorter than int are promoted to int when doing calculations on them. 对短于int变量进行计算时会提升为int It seems that your int type is 16-bit, so shifting it by 16 bits doesn't work right. 看来您的int类型是16位,所以将其移位16位是行不通的。

You should explicitly cast the variables to the result type ( unsigned long ): 您应该将变量显式转换为结果类型( unsigned long ):

address_sum = ((unsigned long)address_byte3<<16) +
              ((unsigned long)address_byte2<<8) +
              (unsigned long)address_byte1;

The last casting is superfluous but doesn't hurt. 最后的转换是多余的,但不会造成伤害。

A shift of a 16-bit int/unsigned , as well explained by @anatolyg will only result in a 16-bit answer. @anatolyg解释了16位int/unsigned移位只会导致16位答案。

I avoid casting, as a general promotion scheme, as sometimes it may narrow the result as code evolves over time and the maintainer uses wider operands. 我避免使用强制转换(作为一般的升级方案),因为有时随着代码随着时间的推移而演变以及维护者使用更宽的操作数,它可能会缩小结果。

Alternatives: 备择方案:

((type_of_target) 1) * : This will insure each operation is at least the width of the target. ((type_of_target) 1) * :这将确保每个操作至少是目标的宽度。

unsigned long address_sum;
...
address_sum = (1UL*address_byte3<<16) + (1UL*address_byte2<<8) + address_byte1;

Assign to the destination and then operate: 分配给目的地,然后操作:

address_sum = address_byte3;
address_sum = address_sum << 8 + address_byte2;
address_sum = address_sum << 8 + address_byte1;

A sneaky, thought not pleasant looking 1-line alternative. 偷偷摸摸的,看起来不愉快的单行替代品。 Recall * + higher order precedence than shift 召回* +优先级高于移位

address_sum = (0*address_sum + address_byte3 << 16) + 
              (0*address_sum + address_byte2 <<  8) + address_byte1;

Consider @Eugene Sh. 考虑@Eugene Sh。 concern and use 8-bit unsigned "bytes". 关注并使用8位无符号“字节”。

My preference is a variation on chux 我的喜好是chux的变化

bigger declaration address; 更大的申报地址; byte declaration a,b,c; 字节声明a,b,c;

address =a; address<<=8;
address|=b; address<<=8;
address|=c;

Despite being the most verbose all of the answers thus far should optimize into basically the same code. 尽管最冗长,但到目前为止,所有答案都应优化为基本相同的代码。 But would have to test the specific compiler to see. 但是将不得不测试特定的编译器才能看到。 Can the 8051 shift more than one bit at a time per instruction anyway? 无论如何,8051是否可以一次将一条指令一次移位一位以上? Dont remember. 不记得了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM