Mam uint8_t, który powinien zawierać wynik obliczenia bitowego. Debugger twierdzi, że zmienna jest ustawiona prawidłowo, ale kiedy sprawdzam pamięć, Var jest zawsze o 0. Kod przechodzi jak Var to 0, bez względu na to, co mówi debugger. Oto kod:

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 uint8_t, path_table's a uint64_t i current_bit's a uint8_t. Próbowałem je wszystkie utint64_t, ale nic się nie zmieniło. Próbowałem też używać niepodpisanego długiego długiego zamiast. Nic więcej.

Kod zawsze wprowadza klauzulę. Chip's Atmega4809 i używa UINT64_T w innych częściach kodu bez problemów.

Uwaga - Jeśli ktoś zna bardziej wydajny / kompaktowy sposób, aby wyodrębnić pojedynczy bit od zmiennej, naprawdę doceniłbym, gdybyś mógł się podzielić ^^

0
Crystallize 26 luty 2019, 16:49

2 odpowiedzi

Najlepsza odpowiedź

1 jest stałą liczbą całkowitą, typu {X1}}. Wyrażenie 1 << current_bit również ma typ int, ale na 16-bit int, wynik tego wyrażenia jest niezdefiniowany, gdy current_bit jest większa niż 14. Zachowanie jest niezdefiniowane Twoja sprawa jest to wiarygodne, że debugger przedstawia wyniki dla ogólnej ekspresji, która wydaje się niezgodna z obserwowanym zachowaniem. Jeśli użyto zamiast tego stałego unsigned int, a nie, tj. 1u, a następnie wynikową wartość temp byłby dobrze zdefiniowany jako 0, gdy current_bit był większy niż 15, ponieważ Wynik lewej zmiany wynosiłby zero.

Rozwiąż ten problem, wykonując obliczenie na tyle typu, aby utrzymać wynik. Oto zwarty, poprawny i dość jasny sposób, aby poprawić swój kod, aby to zrobić:

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

Lub jeśli path_table ma niepodpisany typ, wolę to, choć jest to więcej odejścia od oryginału:

DS18B20_send_bit(pin, (path_table >> current_bit) & 1);
4
John Bollinger 26 luty 2019, 14:58

Realizacja # 1 Oto, że AVR ma rdzeń technologii 1980-1990S. Nie jest to komputer X64, który przeciąga 64-bitowe numery na śniadanie, ale niezwykle nieefektywny 8-bitowy MCU. Takie jak:

  • Lubi 8 bitowych arytmetyków.
  • Będzie walczyć z 16-bitową arytmetyką, robiąc sztuczki z rejestrami indeksu 16-bitowego, podwójnymi akumulatorami lub dowolnymi 8-bitowymi rdzeniowymi sztuczkami preferuje.
  • Dosłownie zajmuje wieki, aby wykonać 32-bitowe arytmetyczne, dzięki inline biblioteki oprogramowania.
  • Prawdopodobnie stopi się przez podłogę, jeśli próbuje 64-bitowy arytmetykę.

Zanim zrobisz cokolwiek innego, musisz pozbyć się wszystkich 64-bitowej arytmetyki i radykalnie zminimalizować użycie 32-bitowego arytmetycznego. Kropka. Nie powinno być pojedynczej zmiennej uint64_t w swoim kodzie lub robisz to bardzo źle.


Dzięki temu objawieniu pojawia się również, że wszystkie 8-bitowe MCU zawsze ma typ int, który ma 16 bitów.

W kodzie 1<<current_bit stała liczba całkowita 1 jest typu int. Znaczenie, że jeśli current_bit jest 15 lub większa, przesuwasz bitów do znaku tego tymczasowego {x4}}. To zawsze jest błąd. Ściśle mówiąc to niezdefiniowane zachowanie. W praktyce możesz skończyć z losową zmianą znaku swoich numerów.

Aby tego uniknąć, nigdy nie używaj żadnej formy operatorów bitowych na podpisanych numerach. Podczas mieszania stałych liczb całkowitych, takich jak 1 za pomocą operatorów bitowych, zmień je na 1u, aby uniknąć błędów takich jak wymienione.


Jeśli ktoś zna bardziej wydajny / kompaktowy sposób, aby wyodrębnić pojedynczy bit ze zmiennej, naprawdę doceniłbym, gdybyś mógł się podzielić

Najbardziej wydajny sposób w C oznacza: {x0}}. Należy to przetłumaczyć na instrukcję "oddziału IF Bit Set".


Moja ogólna rada byłaby zdezakkładnik łańcucha narzędzia i zobacz, jaki kod maszyny, który faktycznie generowany kod CZ. Nie musisz być guru asemblera, aby go przeczytać, zerkanie w Instrukcja Ustaw powinien wystarczyć.

3
Lundin 26 luty 2019, 15:08