我有一个uint8_t,其中应包含按位计算的结果。调试器说变量设置正确,但是当我检查内存时,var始终为0。无论调试器告诉我什么,代码都会像var为0一样进行。这是代码:
temp = (path_table & (1 << current_bit)) >> current_bit;
//temp is always 0, debugger shows correct value
if (temp > 0) {
DS18B20_send_bit(pin, 0x01);
} else {
DS18B20_send_bit(pin, 0x00);
}
温度是uint8_t
,路径表是uint64_t
,而电流位是uint8_t
。我试图使它们全部为uint64_t,但没有任何改变。我也尝试使用unsigned long long int代替。没事了。
代码始终输入else子句。 Chip的Atmega4809,并在代码的其他部分使用uint64_t没有问题。
注意-如果有人知道一种更有效/更紧凑的方法来从变量中提取单个位,如果您可以共享^^
,我将不胜感激。答案 0 :(得分:4)
1
是一个整数常量,类型为int
。表达式1 << current_bit
的类型也为int
,但是对于16位int
,当current_bit
大于14时,该表达式的结果是不确定的。那么,在您的情况下,调试器可能会给出总体表达式的结果,该结果似乎与观察到的行为不一致。如果改用unsigned int
常量 ie 1u
,则只要current_bit
大于15,就将temp的结果值正确定义为0。左移的结果将为零。
通过以足以保存结果的类型执行计算来解决此问题。这是一种紧凑,正确且非常清晰的方法来纠正您的代码以实现此目的:
DS18B20_send_bit(pin, (path_table & (((uint64_t) 1) << current_bit)) != 0);
或者,如果path_table
具有无符号类型,那么我更喜欢这种类型,尽管它与您的原始版本有所不同:
DS18B20_send_bit(pin, (path_table >> current_bit) & 1);
答案 1 :(得分:3)
实现#1是AVR是1980-1990年代的技术核心。它不是x64早餐机可以咀嚼64位数字,而是效率极低的8位MCU。因此:
在执行其他任何操作之前,您需要摆脱所有64位算术并从根本上最小化32位算术的使用。期。您的代码中不应包含uint64_t
的单个变量,否则您做得非常非常错误。
与此同时,所有8位MCU始终具有int
类型,即16位。
在代码1<<current_bit
中,整数常量1
的类型为int
。这意味着如果current_bit
为15或更大,您将把位移入此临时int
的符号位。这始终是一个错误。严格来说,这是未定义的行为。实际上,您可能最终会随机更改数字的符号。
为避免这种情况,切勿对带符号的数字使用任何形式的按位运算符。将1
之类的整数常量与按位运算符混合时,请将其更改为1u
以避免出现上述错误。
如果有人知道一种更有效/更紧凑的方法来从变量中提取单个位,我将非常感谢您能共享
C语言中最有效的方法是:uint8_t variable; ... if(variable & (1u << bits))
。这应该转换为相关的“如果置位则分支”指令。
我的一般建议是找到您的工具链的反汇编程序,并查看C代码实际生成的机器代码。您不必是汇编专家也可以阅读它,窥视instruction set就足够了。