位移位不正确?
Bit shifting not shifting correctly?
我正在使用 Si Labs IDE 用 C 语言对 8051 进行编程。我目前有三个字节:address_byte3, address_byte2, and address_byte1
。然后我将变量 address_sum
初始化为 unsigned long int
然后对其进行以下操作...
address_sum=(address_byte3<<16)+(address_byte2<<8)+(address_byte1);
如果 address_byte3, address_byte2, & address_byte1
是 0x92, 0x56, & 0x78
,这个操作会让我相信加载到 address_sum
的值将分别是 0xXX925678
。相反,我得到 0xXX005678
的值。我的逻辑似乎很合理,但我又是编写代码的人,所以我有偏见,可能会因自己的无知而蒙蔽双眼。有没有人知道为什么 address_byte
的值是 "lost"?
谢谢。
短于 int
的变量在对它们进行计算时被提升为 int
。您的 int
类型似乎是 16 位的,因此将其移动 16 位不正确。
您应该将变量显式转换为结果类型 (unsigned long
):
address_sum = ((unsigned long)address_byte3<<16) +
((unsigned long)address_byte2<<8) +
(unsigned long)address_byte1;
最后一次施法是多余的,但不会造成伤害。
16 位 int/unsigned
的移位,正如 所解释的那样,只会产生 16 位的答案。
我避免转换,作为一般的推广方案,因为有时它可能会缩小结果,因为代码随着时间的推移而发展并且维护者使用更广泛的操作数。
备选方案:
((type_of_target) 1) *
:这将确保每个操作 至少 目标的宽度。
unsigned long address_sum;
...
address_sum = (1UL*address_byte3<<16) + (1UL*address_byte2<<8) + address_byte1;
赋值到目的地再操作:
address_sum = address_byte3;
address_sum = address_sum << 8 + address_byte2;
address_sum = address_sum << 8 + address_byte1;
一个偷偷摸摸的,认为看起来不愉快的 1 行替代品。召回 * +
比 shift
更高的顺序优先级
address_sum = (0*address_sum + address_byte3 << 16) +
(0*address_sum + address_byte2 << 8) + address_byte1;
考虑 问题并使用 8 位无符号 "bytes"。
我喜欢 chux 的变体
更大的申报地址;
字节声明 a,b,c;
address =a; address<<=8;
address|=b; address<<=8;
address|=c;
尽管到目前为止所有答案都是最冗长的,但应该优化为基本相同的代码。不过得测试具体的编译器才能看。无论如何,8051 能否在每条指令中一次移动多于一位?不记得了。
我正在使用 Si Labs IDE 用 C 语言对 8051 进行编程。我目前有三个字节:address_byte3, address_byte2, and address_byte1
。然后我将变量 address_sum
初始化为 unsigned long int
然后对其进行以下操作...
address_sum=(address_byte3<<16)+(address_byte2<<8)+(address_byte1);
如果 address_byte3, address_byte2, & address_byte1
是 0x92, 0x56, & 0x78
,这个操作会让我相信加载到 address_sum
的值将分别是 0xXX925678
。相反,我得到 0xXX005678
的值。我的逻辑似乎很合理,但我又是编写代码的人,所以我有偏见,可能会因自己的无知而蒙蔽双眼。有没有人知道为什么 address_byte
的值是 "lost"?
谢谢。
短于 int
的变量在对它们进行计算时被提升为 int
。您的 int
类型似乎是 16 位的,因此将其移动 16 位不正确。
您应该将变量显式转换为结果类型 (unsigned long
):
address_sum = ((unsigned long)address_byte3<<16) +
((unsigned long)address_byte2<<8) +
(unsigned long)address_byte1;
最后一次施法是多余的,但不会造成伤害。
16 位 int/unsigned
的移位,正如
我避免转换,作为一般的推广方案,因为有时它可能会缩小结果,因为代码随着时间的推移而发展并且维护者使用更广泛的操作数。
备选方案:
((type_of_target) 1) *
:这将确保每个操作 至少 目标的宽度。
unsigned long address_sum;
...
address_sum = (1UL*address_byte3<<16) + (1UL*address_byte2<<8) + address_byte1;
赋值到目的地再操作:
address_sum = address_byte3;
address_sum = address_sum << 8 + address_byte2;
address_sum = address_sum << 8 + address_byte1;
一个偷偷摸摸的,认为看起来不愉快的 1 行替代品。召回 * +
比 shift
address_sum = (0*address_sum + address_byte3 << 16) +
(0*address_sum + address_byte2 << 8) + address_byte1;
考虑
我喜欢 chux 的变体
更大的申报地址; 字节声明 a,b,c;
address =a; address<<=8;
address|=b; address<<=8;
address|=c;
尽管到目前为止所有答案都是最冗长的,但应该优化为基本相同的代码。不过得测试具体的编译器才能看。无论如何,8051 能否在每条指令中一次移动多于一位?不记得了。