Search code examples
cembeddedavravr-gcc

AVR uint8_t doesn't get correct value


I have a uint8_t that should contain the result of a bitwise calculation. The debugger says the variable is set correctly, but when i check the memory, the var is always at 0. The code proceeds like the var is 0, no matter what the debugger tells me. Here's the code:

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);
}

Temp's a uint8_t, path_table's a uint64_t and current_bit's a uint8_t. I've tried to make them all uint64_t but nothing changed. I've also tried using unsigned long long int instead. Nothing again.

The code always enters the else clause. Chip's Atmega4809, and uses uint64_t in other parts of the code with no issues.

Note - If anyone knows a more efficient/compact way to extract a single bit from a variable i would really appreciate if you could share ^^


Solution

  • 1 is an integer constant, of type int. The expression 1 << current_bit also has type int, but for 16-bit int, the result of that expression is undefined when current_bit is larger than 14. The behavior being undefined in your case, then, it is plausible that your debugger presents results for the overall expression that seem inconsistent with the observed behavior. If you used an unsigned int constant instead, i.e. 1u, then the resulting value of temp would be well defined as 0 whenever current_bit was greater than 15, because the result of the left shift would be zero.

    Solve this problem by performing the computation in a type wide enough to hold the result. Here's a compact, correct, and pretty clear way to correct your code to do that:

    DS18B20_send_bit(pin, (path_table & (((uint64_t) 1) << current_bit)) != 0);
    

    Or if path_table has an unsigned type then I prefer this, though it's more of a departure from your original:

    DS18B20_send_bit(pin, (path_table >> current_bit) & 1);