Zagwozdka w C Keil.

W dniu poniedziałek, 11 lutego 2019 14:27:54 UTC+1 użytkownik Mateusz Viste napisał:

Wiem, że rozmawiamy trochę z przymrużeniem oka, więc miałem kiedyś przygodę, kiedy utrzymywana przeze mnie paczka (co gorsza, w Pythonie) przestała się budować. Tam był kod w C który był generowany automatycznie, a narzędzia do współpracy Python - C na pewnym etapie przestawiły flagi kompilatora z domyślnego "ANSI C z typowymi bajerami" na "brak wstępu dla młodzieży, wyrzucaj error przy czymkolwiek czego nie można według C89". Wszystko dzięki temu, że generowany kod miał "int i;" przed forem a nie na początku funkcji. Wtedy się dowiedziałem, że tego nie było w standardzie bo wszystkie kompilatory C jakich w życiu używałem nie miały co do tego obiekcji;)

Ja patrzę z punktu widzenia kogoś, kto czasem napisze coś na "normalny" komputer i chyba nigdy nie udało mi się napisać programu w C, który używa poza jakimiś niekrytycznymi pętlami po 100 elementach któregokolwiek z typów danych z C89. Standard C w tym zakresie jest spuścizną po czasach Unixa, kiedy starano się zrobić jeden przenośny język oprogramowania i system operacyjny obejmujący miriadę komputerów. Efekt jest taki, że w kontekście zwykłego x86-64 windowsowy long ma 32 bity, a uniksowy 64 i obydwa podejścia są zupełnie koszerne pod względem standardu. Long long rzeczywiście jest sposobem na wymuszenie zmiennej, która będzie miała te >= 64 bity ;)

Pozdrawiam,

Reply to
kropelka
Loading thread data ...

Ale przecież typy danych w C89 są całkiem normalne: char, short, int, long... Ich szerokości mogą zmieniać się z jednego komputera na drugi (np. taki int może mieć raz 16, raz 32, a innym razem 64 bity), ale to wszystko jest zgodne z C89. long natomiast ma zawsze co najmniej 32 bity

- w jakich zastosowaniach jest potrzeba więcej na "normalnym" komputerze?

Mi zdarza się (rzadko, ale jednak) użyć uint64_t do liczenia jakichś naprawdę dużych wielkości, np. do zliczania cykli CPU, a czasem nawet po _uint128_t (gcc) sięgnę jak potrzebuję popracować na adresach IPv6. Ale to naprawdę sporadyczne przypadki, stąd ciekaw jestem co takiego piszesz że w C89 nie da się :)

Mateusz

Reply to
Mateusz Viste

No więc znalazłem chwilę aby podjechać do klienta i popatrzeć dokładnie w kod. Na wstępie małe usprawiedliwienie - procedura była napisana na 8051 i uruchomiona na jednym z pierwszych PLC jakie zrobiłem, w latach 90, ale stosowana też później*. W tamtych czasach wydawało mi się, że ogarniam podstawy C :)

W maszynie którą diagnozowałem definicja zmiennej DEL_STEP była o zgrozo jako unsigned char. Nie zwróciłem na to uwagi, choć zauważyłem, że sprawdzany jest tylko młodszy - przekazany - bajt zmiennej z którą wywołano funkcję. Wygląda więc na to, że kompilator miał rację.

Po zmianie definicji na unsigned int kompilator robi OLR na obu połówkach zmiennej DEL_STEP a następnie sprawdza czy wynik operacji jest zerowy. Bardzo ładne rozwiązanie moim zdaniem.

Zrobiłem jeszcze jedną rzecz. Ponieważ jak zauważyliście, nie ma gwarancji, że sprawdzenie 16 bitów będzie poprawne w przypadku gdy przerwanie może je zmienić, podłączyłem oscyloskop, persystencję na nieskończoną i obserwowałem czas generowany przez procedurę. Zdarzały się błędnie odliczone interwały, ale nie za często. Zrobiłem jak Mateusz podpowiedział - flaga w przerwaniu modyfikującym zmienną. Nie złapałem żadnego błędnego odliczenia.

Tak więc przepraszam, ale wychodzi na to, że sensacji nie ma, kompilator jednak dawał radę, a ja znowu się czegoś nauczyłem :)

Dzięki wszystkim za pomoc.

Miłego. Irek.N.

  • w późniejszych wersjach kodu (trochę inna wersja PLC) już była poprawna definicja jako typ 16 bitowy, czyli kiedyś to zauważyłem, poprawiłem i zapomniałem :(
Reply to
Irek.N.

Przynajmniej jakaś pociecha dla mnie - myślałem, że tylko ja mam sklerozę ;)

Reply to
stary grzyb

Użytkownik "stary grzyb" snipped-for-privacy@onet.pl napisał w wiadomości news:q3vfp6$rq6$ snipped-for-privacy@dont-email.me...

Panie, ja tam nie mam sklerozy, odpukać! Puk puk... Kto tam? :):)

Kiedyś mi prawie półtora roku zajęło, aby złapać, dlaczego przy pracy z TC, wyskakuje mi pewne (niepożądane) okienko. Banał, że śmiać sie chce :) Czemu tyle? Bo stale zapomniałem wyłapać okoliczności, w jakich się to staje.

Reply to
HF5BS

W dniu 2019-02-12 o 23:02, stary grzyb pisze:

Zdarzyło mi się kiedyś, że postanowiłem, że coś muszę zmodyfikować w jednym programie. Wyszukałem miejsce gdzie to należy poprawić - a tu "już ktoś to zrobił". Według daty pliku wynikało, że góra miesiąc temu :( P.G.

Reply to
Piotr Gałka

Użytkownik "Irek.N." napisał w wiadomości grup dyskusyjnych:q3vee4$o74$ snipped-for-privacy@node1.news.atman.pl...

uzyc niewlasciwy typ - zdarza sie. Ale nie spojrzec jaki to typ przy sprawdzaniu/szukaniu bledu ... czas na lecytyne :-)

Typowe.

Czyli potrafi przerwanie trafic miedzy dwie instrukcje ? No w sumie - zawsze miedzy dwie trafia, tylko kwestia prawdopodobienstwa, kiedy trafi miedzy dwie istotne.

A tych instrukcji przy ORL byc moze nawet wiecej.

Rozumiem, ze najpierw zmieniles typ zmiennej na int ?

Ale nie bardzo rozumiem - przerwanie ustawia flage, modyfikuje zmienna, gasi flage ? na przetwarzanie w procesie głownym nie ma to znaczenia - sprawdzi sobie, ze flagi nie ma, zacznie czytac zmienna ... i tu przerwanie przychodzi. Co innego gdy uzywa zmiennej przerwanie wyzszego poziomu.

Ja bym tam wylaczyl przerwania na czas sprawdzenia, to raptem kilka instrukcji, ale w pojedynczym while zaprogramowac to trudno.

A swoja droga - czy Keil sam ich nie wylacza ? Dla zmiennych volatile powinien.

Ale o co chodzi - powiekszyles wartosc opoznienia ponad 255, i sie okazalo, ze nie czeka tyle co powinien ?

J.

Reply to
J.F.

W dniu 2019-02-13 o 11:28, J.F. pisze:

W avr studio nie wyłącza, i keil pewnie też, w gcc jest do tego osobna sekcja, atomic block się nazywa i w niej sie takie porównania robi.

Reply to
Janusz

Ja mam nawet tabletki na poprawę pamięci, ale co z tego, skoro ... zapominam je brać :)

Reply to
stary grzyb

Dla mnie bardzo eleganckie :)

W * pisałem, że już kiedyś to znalazłem. Oczywiście że poprawiłem :)

Procedura ustawiająca zmienną modyfikowaną w przerwaniu ustawia flagę i czeka na jej zgaszenie. Przerwanie odlicza i jak doliczy to gasi flagę.

Niepotrzebna zabawa. Poza tym wprowadzasz dodatkowy jitter ;)

Niestety ale ignoruje zupełnie volatile, a nie powinien moim zdaniem.

No ba, dajesz operatorowi możliwość ustawiania parametru w zakresie

100-500, a tu zonk, czasami maszyna się buntuje :)

Miłego. Irek.N.

Reply to
Irek.N.

Ostro :) Ja czasami robie błąd składni w kodzie, jak wiem że będę musiał zaglądnąć w jakieś miejsce przy następnej okazji. Przy kompilacji błąd wskazuje gdzie zaglądnąć, a tam już opis robi swoje :) Trza sobie radzić jak szare zszarzały :(

Miłego. Irek.N.

Reply to
Irek.N.

Irek.N. snipped-for-privacy@jakis.taki.jest.pl> napisał(a):

Jeśli to C, to można skorzystać z dyrektywy preprocesora żeby nie psuć dobrego kodu: #error "Tu zrobic zmiany"

Reply to
Grzegorz Niemirowski

95% mojego kodu to ST, reszta to raczej VB niż C i pokrewne.

Miłego. Irek.N.

Reply to
Irek.N.

W dniu 2019-02-13 o 21:13, Irek.N. pisze:

Ale volatile oznacza tylko tyle że kompilator nie zoptymalizuje zmiennej aby ją np wyciąć albo trzymać tylko w rejestrach, taka zmienna będzie zawsze trzymana w pamięci, a kto i kiedy ją modyfikuje czy czyta to go nie obchodzi.

Reply to
Janusz

To nawet nie o to chodzi. Im mniej zaśmiecasz swoją pamięć, tym lepiej. Ja często zapisuję sobie rzeczy, o których pewnie bym pamiętał, właśnie po to, żeby nie musieć pamiętać :) Zyskuję wtedy taki dziwny spokój, że coś do zrobienia już jest zapisane i nie muszę o tym pamiętać (czyli tak naprawdę myśleć).

To, czy pamiętam o zajrzeniu do notatek i czy w ogóle nad nimi panuję, to zupełnie osobny temat. Kiedyś je uporządkuję. To również jest zapisane.

Reply to
Queequeg

Jak masz w głowie, że to musi być int, to możesz przeoczyć :)

Wbrew intuicji -- nie :) Modyfikator `volatile` oznacza tylko tyle, że kompilator nie może robić założeń co do zawartości zmiennej opatrzonej tym modyfikatorem, bo zmienna może zmienić wartość poza ścieżką wykonania (np. jest to sprzętowy rejestr, lub inny wątek ją modyfikuje, lub właśnie przerwanie). `volatile` nie oznacza, że kompilator gwarantuje atomiczny dostęp do zmiennej (czyli że wyłączy wszystko inne, co może zmienić jej wartość w trakcie dostępu -- czy to wątki, czy przerwania, czy zewnętrzny sprzęt).

AVR ma to rozwiązane w ten sposób:

formatting link

Reply to
Queequeg

No ale czy nie powinien ? Bo skoro sie moze zmienic w sposob niekontrolowany, to jak mozna wierzyc wartosci odczytanej nieatomicznie ?

No i widac ja sie te pomysly nadaja do prostego: while (ctr) ;

:-)

J.

Reply to
J.F.

G..o prawda.

Reply to
Janusz

Skąd wiesz?

Zrób test. Napisz funkcję:

int i; void fn(void) { do { } while (i != 42); }

Skompiluj z optymalizacją, zobacz kod. Potem dodaj volatile, zobacz kod.

Sprawdziłem na raspi (arm), gcc -O2 -S.

Bez volatile:

#v+ ldr r3, .L5 ldr r3, [r3] ; tu ładuje zmienną do rejestru .L2: cmp r3, #42 ; tu porównuje rejestr bne .L2 ; tu skacze z powrotem do porównania #v-

Z volatile:

#v+ ldr r2, .L5 .L2: ldr r3, [r2] ; tu ładuje zmienną cmp r3, #42 ; tu porównuje bne .L2 ; tu skacze z powrotem do załadowania #v-

Podobnie na amd64. Bez volatile:

#v+ movl i(%rip), %eax ; tu ładuje zmienną .p2align 4,,10 .p2align 3 .L2: cmpl $42, %eax ; tu porównuje jne .L2 ; tu skacze z powrotem do porównania #v-

Z volatile:

#v+ .L2: movl i(%rip), %eax ; tu ładuje zmienną cmpl $42, %eax ; tu porównuje jne .L2 ; tu skacze z powrotem do załadowania #v-

Jeszcze ciekawiej się robi, gdy dodasz modyfikator `static`. Bez volatile, arm:

#v+ .L2: b .L2 #v-

Bez volatile, amd64:

#v+ .L2: jmp .L2 #v-

Dlaczego tak? Bo kompilator wie, że inna jednostka kompilacji nie zmieni wartości tej zmiennej (bo jest statyczna, widoczna tylko w obrębie danej jednostki kompilacji), więc nie ma sensu żadne sprawdzanie, bo zmienna i tak jest zero (bo zmienne globalne są inicjalizowane zerami; spróbuj zamiast 42 wstawić 0 i zobacz, jaki kod wtedy kompilator wygeneruje).

Oczywiście z volatile działa tak, jak byśmy chcieli.

Reply to
Queequeg

A co konkretnie?

Nie mylę, może nieprecyzyjnie się wyraziłem. AVR ma wspomniane mechanizmy, których programista może użyć, jeśli interesuje go atomiczny dostęp lub tak naprawdę jakakolwiek inna sekcja krytyczna.

Tak (i prawidłowo), o tym właśnie piszę.

Reply to
Queequeg

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.