Elektroda.pl
Elektroda.pl
X

Search our partners

Find the latest content on electronic components. Datasheets.com
Elektroda.pl
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

[ARM][C] Specyficzne dylematy, jakość kodu

MrKsawery 12 Nov 2017 10:37 801 19
Tespol
  • #1
    MrKsawery
    Level 13  
    Witam.
    Parę pytań, przemyśleń, proszę o wypowiedzenie się. Temat dotyczy programowania embedded C głownie mikrokontrolerów raczej większych 32 bitowych.

    1. Stosowanie wielu zmiennych globalnych jest bee

    Czy w świecie embedded bez dynamicznej alokacji pamięci da się inaczej? Zakładając, że mamy jakieś stałe duże struktury globalne (zawierające mnóstwo zmiennych globalnych) w pamięci i pobieramy wskaźnik do nich.
    A co z takim:
    Code: c
    Log in, to see the code


    2. Duża struktura danych zagnieżdżonych wielokrotnie – pobieranie adresu do struktury w celu pobrania lub zapisania wartości.
    Code: c
    Log in, to see the code

    3. Stosowanie zmiennych volatile

    Najprościej można powiedzieć: kiedy jakaś zmienna jest wykorzystywana w przerwaniu oraz programie głównym użyj volatile (oczywiście są też inne zastosowania).
    Code: c
    Log in, to see the code


    Czy powyższy kod według Was jest wystarczająco bezpieczny? Co w przypadku zapisywania odebranego bufora typu volatile do kolejki. Stosując memcpy otrzymujemy ostrzeżenie o zmianie typu volatile uint8_t * na uint8_t * - wielu programistów uważa łączenie volatile z non volatile za nieprzewidywalne, co wtedy - lepiej samemu zrobić funkcję ładującą do kolejki bez konwersji volatile z na non volatile?

    4. Synchronizacja przerwania z programem głównym

    Wielu programistów uważa takie podejście za dobrą praktykę
    - w przerwaniu ustawia się jakieś dane
    - w programie głównym blokuje się to przerwanie na czas przekopiowania tej wartości do zmiennej pomocniczej, która następnie będzie wykorzystywana.

    Co daje takie podejście? Czy mądrym jej blokować przerwania co prawda na krótki czas? Czy po odblokowaniu przerwanie które hipotetycznie pojawiło by się w czasie wyłączenia byłoby obsłużone?

    5. Zastosowanie dodatkowej blagi busy do synchronizacji

    Przykład: program główny operuje na zmiennej, zaczął część operacji i nastąpiło przerwanie które zmieniło wartość, dalej program będzie operował już na innej zmiennej nie wiedząc o tym. Robiąc flagę busy przerwanie nie mogłoby nadpisać, ale co nową informacją? Wiem że są kolejki, ale tutaj chodzi o proste zmienne typu flagi, małe bufory, pojedyncze wartości.

    6. Ładowanie odebranego bufora w przerwaniu

    Podprogram przerwania powinien być mały i szybki, czy takie podejście można przyjąć? Co w takim przypadku: program główny zaczął wyciągać z kolejki dane przyszło przerwanie i wpisało kolejny element do kolejki i zmieniło indeksy kolejkowe - zależnie od implementacji kolejki head i tail itd.
    Oczywiście zakładamy bardzo częste przychodzenie danych i rygory czasowe.
    Czy kolejka do której ładujemy w przerwaniu powinna być volatile?

    7. Blokowanie pamięci
    Code: c
    Log in, to see the code

    Po co stosować taki twór? Co to daje w przypadku mikrokontrolerów ARM Cortex M0,1,4...

    8. Kopiowanie buforów po 32 bitach w celu przyśpieszenia na uC 32 bitowym
    Czy dobrą praktyką jest dodawanie w strukturze danych aby osiągnąć wypełnienie do 32 bitów aby przyśpieszyć kopiowanie, jak to zaimplemetować, czy memcpy tak działa? Czy kopiuje po bajtach?

    Jestem świadomy że popełniłem wiele uproszczeń przykładów i wiele uproszczeń. Proszę Was o wypowiedzenie się w tym temacie i z góry dziękuję.
  • Tespol
  • #2
    chudybyk
    Level 31  
    W większości Twoich pytań są już jakieś odpowiedzi.
    Od siebie dodam, że warto pokusić się o używanie C++ nawet w środowiskach embedded standalone. Operatora "new" teoretycznie się nie użyje (choć jak się pokombinuje...), ale obiektowość ma wiele innych zalet.
    Warto przyswoić sobie sposób myślenia z języków wyższych poziomów jak Java ( np. ukrywanie implementacji), próbować implementować wzorce projektowe, czy też przed kodowaniem narysować sobie kilka schematów UML. Dobry projekt programu to połowa sukcesu, a drobniejsze zagwozdki jak używanie volatile staną się oczywiste lub znikną.

    Tym mnie zaskoczyłeś:
    asm volatile ( : : : memory); -> to bariera, która nakazuje kompilatorowi przeorganizować sposób odwołań do zmiennych, żeby za barierą od nowa organizować optymalizację. Coś jak chwilowe volatile dla wszystkich zmiennych.
    Muszę przyznać, że nigdy tego nie użyłem i musiałem pogooglać. :-)
  • #3
    MrKsawery
    Level 13  
    Oczywiście warto stosować aksjomaty obiektowe w programowaniu w C, ale jak bez dynamicznej alokacji nie użyć zmiennej globalnej? Oczywiście można ją ukrywać w pliku C dodatkowo zaopatrywać w static, ale tego się nie obejdzie.

    Dopisałem jak ja bym do tego podszedł, a nie odpowiedziałem sobie, bo nie oczekiwałem odpowiedzi, a raczej komentarza od bardziej doświadczonych programistów języka C.

    Język C++ w przypadku oszczędzania poszczególnych bajtów nie jest najlepszym wyborem.
  • Tespol
  • #4
    JacekCz
    Level 39  
    1. w kwestii formalnej zmienna "static" nie jest globalna.
    Tu są dwa obszary, gdzie język / sposób mówienia o języku ma niuanse.
    Jedno to "dynamika" czy czas istnienia zmiennej (tu static ma wspólne zachowanie z globalnym), z drugiej "zasięg leksykalny", czy da się przywołać identyfikator z innej jednostki kompilacji (tu 'static' jest przeciwieństwem 'globalizmu')
    Co do drugiego, tak, usilnie się zaleca jak najmniejszy zasięg leksykalny. Ale żle użyte 'static' może dawać wielokrotne kopie zmiennej w różnych jednostkach.
    W C++ by to fajnie obronił jako pole statyczne w klasie.

    2. zabezpieczenia wielowątkowe, volatile to obszerny temat (z wieloma przesądami w sieci). To tyle zasygnalizuję, rzecz jest wielokrotnie dyskutowana.

    3. Popieram i to głęboko myśl o C++, nawet bez obszernego użycia biblioteki standardowej, daje wiele pozytywów (i wbrew przesądom nie ma kosztów, o jakich się baja)
    Dodano po 1 [minuty]:
    MrKsawery wrote:

    Język C++ w przypadku oszczędzania poszczególnych bajtów nie jest najlepszym wyborem.


    Mam ochotę dziś powiedzieć to kulturalnie: nie zgadzam się.
    Dodano po 3 [minuty]:
    chudybyk wrote:

    ...Od siebie dodam, że warto pokusić się o używanie C++ nawet w środowiskach embedded standalone. Operatora "new" teoretycznie się nie użyje (choć jak się pokombinuje...), ale obiektowość ma wiele innych zalet.
    Warto przyswoić sobie sposób myślenia z języków wyższych poziomów jak Java ( np. ukrywanie implementacji), próbować implementować wzorce projektowe
    ...


    Popieram. Zacytowałem fragment, ale szersza myśl tez mi się podoba.
    Enkapsulacja (ukrywanie), enum, kontruktor, destruktor, większe bezpieczeństwo typów i inne..,
    Ukrywanie implementacji jest w pełni zrealizowane z C++ (ale pomijane w kiepskich materiałach internetowych). Nie kosztuje to NIC taktów CPU.
    Zagadnienia 4,5 a ZWŁASZCZA 6 ślicznie do tego pasują.
  • #5
    chudybyk
    Level 31  
    Dlaczego dynamiczna allokacja miałaby coś rozwiązywać w kwestii zmiennych globalnych? Raczej robi problemy - łatwo o wyciek pamięci, defragmentacja, narzuty czasowe na allokację...
    Zwykle w ogóle nie trzeba używać zmiennych globalnych. Zasięg widzialności zmiennych nie ma też automatycznego przełożenia na sposób allokacji (statyczne, automatyczne, dynamiczne).
    Zmienne należy tworzyć w sposób, który najlepiej oddaje ich funkcjonalność - czyli statyczne, kiedy trzeba przechować informację poza blokiem w którym zmienna jest zdefiniowana, a w reszcie przypadków wystarczy zmienna automatyczna. Nawet niewielkie tablice można tworzyć automatycznie (zwykle na stosie), bo pamięć będzie odzyskana, gdy program jest poza tym fragmentem bloku.
    Może nie potrafię wyobrazić sobie problemu, który kolegę nurtuje, albo też kolega sobie jakiś problem wymyślił.

    Jeśli w programie trzeba się liczyć z każdym bajtem, to znaczy, że do projektu jest przyjęty mikroprocesor o zbyt małej ilości pamięci RAM.
  • #6
    MrKsawery
    Level 13  
    Problem zmiennej globalnej:
    - system składający się z wielu plików, kilku lub kilkunastu przerwań, dostęp do tej samej struktury opisującej "dane urządzenie" z przerwań oraz wielu innych miejsc.
    - tworząc zmienne w funkcji ograniczamy się do tej funkcji, więc po wyjściu z funkcji pod tym adresem może być coś innego
    - można stworzyć w main tą zmienną aby mieć przez całe życie programu ją pod stałym wskaźnikiem, ale przecież mam osobne pliki .c i .h gdzie tworzę tą strukturę itd w main ie może tego być.

    Jak inaczej chcecie to zrobić? Jedynie dynamicznym lokowaniem sterty. Mowa o języku C, nie C++.

    Problem rozwiązuje zastosowanie zmiennej statycznej, jednak zaleca się nie stosowanie takich zmiennych.
    Code: c
    Log in, to see the code


    Czy to jest poprawne podejście? Lepsze od zmiennej globalnej?

    Zastanawiałem się nad tym ponieważ ostatnim czasem spotkałem się z optymalizowaniem zmiennej globalnej, co mnie bardzo zdziwiło i stąd moja przemyślenia związane z volatile.
  • #7
    JacekCz
    Level 39  
    MrKsawery wrote:

    A co z takim:
    Code: c
    Log in, to see the code

    3. Stosowanie zmiennych volatile

    Najprościej można powiedzieć: kiedy jakaś zmienna jest wykorzystywana w przerwaniu oraz programie głównym użyj volatile (oczywiście są też inne zastosowania).


    jak ktos tak użył volatile wewnątrz funkcji, znaczy że nie rozumie nic w tych sprawach. Ta zmienna i tak nigdy nie będzie 'podkradana' z innych wątków, jest to niemożliwe.
    Volatile ma wiele nieprawdziwych, religijnych przesądów, streszczają się "to nic, że nie rozumiesz, ale użyj jak mowa o przerwaniach". Rzecz ciekawa, jest też źle rozumiane przez słabych programistów w Javie, gdzie jest słowo 'synchronized' (można domniemywać, że tego by chcieli)
    Dodano po 31 [sekundy]:
    MrKsawery wrote:

    A co z takim:
    Code: c
    Log in, to see the code



    To musiało byc w jakiejś "religii C". Trudno powiedzieć, co poeta miał na myśli (oszczędność? enkapsulację? konserwowalność definicji struktury? żaden z celów nie jest spełniony) , ale po paru latach takich eksperymentów wynajdzie C++ .

    EDIT Jestem pewien, że autor tego tricku NIE ROZUMIE zachowania pamięci w C (embedded nie powinien nawet oglądać w telewizji) ... więc nie jestem pewien czy kiedyś wynajdzie C++
    (w Twoim nowszym poście cytujesz na temat tego fragmentu przesądy. Wydajesz się rozsądnym człowiekiem, więc zakładam że to cytaty "gdzieś z internetu")
  • #8
    MrKsawery
    Level 13  
    JacekCz wrote:


    Najprościej można powiedzieć: kiedy jakaś zmienna jest wykorzystywana w przerwaniu oraz programie głównym użyj volatile (oczywiście są też inne zastosowania).


    To wskaźnik na zmienną volatile. To nie jest zmienna tylko wskaźnik.
    Code: c
    Log in, to see the code

    To dwie różne sprawy. Ile programował kolega w czystym C?

    Kolega chyba nie rozumie czym jest volatile w C != volatile JAVA itd

    Ono zapobiega optymalizacji i wkładaniu do rejestrów procesora.

    Dodano po 6 [minuty]:

    JacekCz wrote:

    EDIT Jestem pewien, że autor tego tricku NIE ROZUMIE zachowania pamięci w C (embedded nie powinien nawet oglądać w telewizji) ... więc nie jestem pewien czy kiedyś wynajdzie C++
    (w Twoim nowszym poście cytujesz na temat tego fragmentu przesądy. Wydajesz się rozsądnym człowiekiem, więc zakładam że to cytaty "gdzieś z internetu")



    Nie rozumiem czym kolega się tutaj "podnieca", ale to nie moja sprawa, proszę odpowiedzieć ile programował kolega w C. W takim razie proszę wyjaśnić mi, żebym zrozumiał.

    Przecież obecnie programuję się w dużych korporacjach prawdziwe systemy czasu rzeczywistego np. automotive w języku C.

    Czekam aż kolega pokaże swój dobry przykład jak to dobrze i świadomie zrobić w C, bo krytykować każdy "głupi" potrafi, a pokazać już mało który.
  • #9
    chudybyk
    Level 31  
    MrKsawery wrote:
    Problem zmiennej globalnej:
    - system składający się z wielu plików, kilku lub kilkunastu przerwań, dostęp do tej samej struktury opisującej "dane urządzenie" z przerwań oraz wielu innych miejsc.
    - tworząc zmienne w funkcji ograniczamy się do tej funkcji, więc po wyjściu z funkcji pod tym adresem może być coś innego
    - można stworzyć w main tą zmienną aby mieć przez całe życie programu ją pod stałym wskaźnikiem, ale przecież mam osobne pliki .c i .h gdzie tworzę tą strukturę itd w main ie może tego być.

    Jak inaczej chcecie to zrobić? Jedynie dynamicznym lokowaniem sterty. Mowa o języku C, nie C++.


    Problem jednoczesnego dostępu do zmiennych to fundamentalny problem programowania równoległego. W przypadku przerwań jest jeszcze gorzej, bo przerwania rzadko mogą czekać na coś. Rozwiązaniem mogą być mechanizmy typu semafory/kolejki/itp., albo jak już wspominałeś chwilowe wyłączanie przerwań. Rozwiązanie zazwyczaj zależy od konkretnego przypadku - czasem wystarczy zwykłe volatile, czasem nie.
    Dynamiczna allokacja nic nie zmienia.
  • #10
    JacekCz
    Level 39  
    1. nie wyobrażam sobie programowania embedded, żeby choć raz na miesiąc nie rozwinąć C do ASM i zobaczyć co wychodzi. Z poczucia obowiązku, procedur w korporacji lub własnej ciekawości.

    Dyskusja o funkcji się skończy.
    Znalazł byś statyczny blok pamięci (tzn istniejący przed załadowaniem programu, o jakieś drobne atrybuty różniący się od 'zewnętrznego static' ) i funkcję która na niego "rzekomo inteligentnie" zwraca wskaźnik.

    Kolego, to Ty jesteś zwolennikiem C (jako wydajniejszego itd), więc dobrze wiesz, że w rozwinięciu C nie ma żadnej magii, co napisane, to jest.
    Napisz w "niby-assemblerze" jak to się spodziewasz oszczędności pamięci. Pamięci nie było, i nagle jest? Ukryty malloc() ??? Sam sobie zaprzeczasz.

    2. volatile. Dobrze cytujesz formalną definicję volaitile (nawiasem mówiąc w Javie słowo ma identyczne znaczenie), ale już oczekiwania od tego słowa są "znalezione w internecie".
    Wrzuć to słowo w wyszukiwarkę Elektrody, niejedna święta wojna już była. Np struktury volatile.
    Ze dwa dni temu inny kolega zdumiony odkrył, że 'volatile' nie jest optymalnie wydajnościowo (a chyba jak rozumiem poradnik to obiecywał)

    3. wiele lat. Z każdym rokiem się utwierdzam, jak słaby jest średni poziom C uczony z netu (z zastrzeżeniem, jak w znanym dowcipie o średniej)

    Żeby uspokoić emocje, pomysł magagera który będzie "pseudo-alokował" egzemplarze struktury (z w miarę ukrytej tablicy), nie jest nowy i bywa stosowany. W zamierzchłych czasach biblioteki standardowe C miały taką ukrytą tablicę FILE[] w wymiarze kompilowanym stałą (zwykle 20-50), i z niej zwracały przez fopen(), konieczny był uczciwy zwrot przez fclose()
    Wzorzec ten bywa nazywany pulą, i się to stosuje.
    O wiele fajniej to można zaimplementować w C++.

    natomiast uProcesor ma pewną ilość RAM, i czy radykalnie to zmieni pseudo-alokacja i alokacja prawdziwa?
    Więcej pamięci w segmencie statycznym, czy dynamicznym, której suma jest slała?
    Biblioteki standardowe na uP mają to dość sprytnie zrobione. Jak nie jestem fanem Arduino, tam tak jest

    Dodano po 12 [minuty]:

    chudybyk wrote:
    ...Rozwiązanie zazwyczaj zależy od konkretnego przypadku - czasem wystarczy zwykłe volatile, czasem nie.
    ...


    W obrębie tego otwartego stwierdzenia, ja zajmuję stanowisko że v. niemal zawsze jest konieczną podstawą, ale (bardzo) rzadko załatwia całość potrzeby.
    Semafory, Disable Interrupt (czasem pasuje funkcjonalność naturalnie dostarczana przez procesor), to jest to.
  • #11
    MrKsawery
    Level 13  
    Code: c
    Log in, to see the code


    Ten kawałek kodu nie uważam za coś niezwykłego, po prostu tworzy zmienną globalną, z ograniczeniem jej widoczności a poprzez getter przekazuję wskaźnik na nią aby mieć dostęp do jej pól, jest to zwyczajna ukryta struktura, która jest w pamięci.

    volatile RX_Protocol * to wskaźnik na zmienną volatile, być może nie jest to potrzebne, ale po co zostawiać niejasności?

    Rozumiem, że kolega sugeruje mój poziom wiedzy, w takim razie co w tym podejściu jest złego?
  • #12
    JacekCz
    Level 39  
    MrKsawery wrote:
    Code: c
    Log in, to see the code


    Ten kawałek kodu nie uważam za coś niezwykłego, po prostu tworzy zmienną globalną, z ograniczeniem jej widoczności a poprzez getter przekazuję wskaźnik na nią aby mieć dostęp do jej pól, jest to zwyczajna ukryta struktura, która jest w pamięci.

    volatile RX_Protocol * to wskaźnik na zmienną volatile, być może nie jest to potrzebne, ale po co zostawiać niejasności?


    Nie jest to kod niezwykły. Rzecz w tym, że jest to kod pozorny, niczemu nie służy.

    Zadałem już wcześniej pytanie, co było celem: enkapsulacja, oszczędność, konserwowalność - nie udzieliłeś odpowiedzi.
    Jeśli rozumiem, przestajesz bronić tezy, że wewnętrzny static magicznie daje oszczędność?

    MrKsawery wrote:
    .... być może nie jest to potrzebne, ale po co zostawiać niejasności? ...


    a)
    W tytule wątku pytasz o jakość kodu.
    Ludzie od rygorystycznej jakości kodu *) by Ci powiedzieli: jeśli jakaś konstrukcja (np słowa kluczowe) nie są potrzebne, to WPROWADZA NIEJASNOŚĆ.

    b)
    A już w sensie węższym, najbardziej gorące słowo C. Olbrzymia większość 'volatile' na elektrodzie jest obietnicą (intencją autora) która nie jest do utrzymania.
    Co OBIECUJE volatile static struktura? Czego się po tym spodziewasz? Obroń to, przecież może masz rację.

    EDIT: spieram się z Tobą, bo szanuję, że myślisz, choć inaczej ode mnie. Ja na wiele bzdur C+uP w ogóle się nie odzywam (dodam, u statystycznego kolegi z tej branży w ogóle nie ma pytania o zmienną globalną)

    *) nie mam pod ręką jakiegoś YT na gruncie C (choć są na gruncie Javy/C#). To jest problem ogólniejszy, większość materiałów C "w internecie" ściąga w dół, a nie motywuje do góry. Ale zasady są wspólne na gruncie wszystkich języków programowania.
  • #13
    MrKsawery
    Level 13  
    MrKsawery wrote:

    z ograniczeniem jej widoczności a poprzez getter...

    Ale ja nigdy nie mówiłem że static nie daje oszczędności, zależy mi na ukrywaniu tej zmiennej globalnej czyli enkapsulacji i tyle.... żeby nie mieć w kodzie stale do niej odwołania, oszczędności nie ma żadnej.

    Dodano po 3 [minuty]:

    Stworzenie wskaźnika jako volatile nic nie zmienia z pewnością, choć słyszałem pogłoski że zmienia, ale jednak kompilator daje komunikat o tym:
    Code: c
    Log in, to see the code

    Można zrzutować, ale chyba dobrą praktyką nie jest zostawienia warningów?
    Z tego co wiem takie coś powinno być jawnie rzutowane, nawet jeśli w asemblerze dostanie się ten sam kod.

    Dodano po 7 [minuty]:

    JacekCz Chyba mi nie powiesz, że doświadczony programista nie zrozumie po co robi się taką jawną konwersję, rzutowanie itd?
  • #14
    JacekCz
    Level 39  
    MrKsawery wrote:

    Stworzenie wskaźnika jako volatile nic nie zmienia z pewnością, choć słyszałem pogłoski że zmienia, ale jednak kompilator daje komunikat o tym:
    Code: c
    Log in, to see the code

    Można zrzutować, ale chyba dobrą praktyką nie jest zostawienia warningów?
    Z tego co wiem takie coś powinno być jawnie rzutowane, nawet jeśli w asemblerze dostanie się ten sam kod.


    Moja sekwencja myślenia jak kompilator daje warningi sugerujące rzutowanie, analiza "top down" (oczywiście słowo użyłem nieco umownie), często prowadzi do tego, że już pierwsze użycie ma nieprawidłowe modyfikatory. Żeby nie gadać w kółko o nieszczęsnym volatile, np. const propagowane przez kilka poziomów (w tym bardzo pouczająca obiektowa metoda z const).
    Raczej czyścić przyczyny, niż rzutować na oślep (tzw pudrowanie syfu)

    MrKsawery wrote:

    JacekCz Chyba mi nie powiesz, że doświadczony programista nie zrozumie po co robi się taką jawną konwersję, rzutowanie itd?


    Nie wiem, czy to do mnie pytanie ;)
    Ale nawet dobry programista ma zły dzień, przejmuje projekt, presja politycznie ważnej poprawki, ALBO wraca po długiej przerwie do własnego (chyba gorsze niż projekt w sposób oczywisty obcy)


    Rzutowanie to wróg (w C nie ma ClassCastException!!!).
    Programista moze być do tego zmuszony (np dziwne API, podawanie danych integer/void pointer do widgetów Win32)
    Jejka, jak mi piórka wybrało przy zmianie 32->64b. Kompilator wystawił inne dziwne miejsca, ale rzutowanie przykryło minę.

    Sam podałeś przykład: rzutowanie, bo tak mówią.
  • #15
    MrKsawery
    Level 13  
    Czyli z Twojej wypowiedzi wynika,że volatile jest tak wskawione bezzasadnie i przez to pogłębia się problem?
    Otóż nie, nie wstawiając volatile, program jest optymalizowany i nie będzie działał.
    A rzutując wskaźnik na wskaźnik na typ volatile (a nie wskaźnik volatile) nic się nie zmienia w kodzie wyjściowym.

    Po co bezpieczeństwo typów nie lepiej pomyśleć co się chce osiągnąć?

    Dodano po 2 [minuty]:

    JacekCz Jak Ty byś rozwiązałem ten "problem" nie stosował volatile w tej sytuacji, nie robił rzutowania? Każdy pomysł zły, ale sam nic nie potrafisz zaproponować?
  • #16
    JacekCz
    Level 39  
    MrKsawery wrote:
    Czyli z Twojej wypowiedzi wynika,że volatile jest tak wskawione bezzasadnie i przez to pogłębia się problem?
    Otóż nie, nie wstawiając volatile, program jest optymalizowany i nie będzie działał.
    A rzutując wskaźnik na wskaźnik na typ volatile (a nie wskaźnik volatile) nic się nie zmienia w kodzie wyjściowym.

    Po co bezpieczeństwo typów nie lepiej pomyśleć co się chce osiągnąć?
    Dodano po 2 [minuty]:
    JacekCz Jak Ty byś rozwiązałem ten "problem" nie stosował volatile w tej sytuacji, nie robił rzutowania? Każdy pomysł zły, ale sam nic nie potrafisz zaproponować?


    Nie sposób wypowiadać się w kształcie CAŁY program będzie zoptymalizwoany i CAŁY nie będzie działał.
    Każdy przypadek volatile trzeba by omówić oddzielnie. Kol. pyta o fragmenty, więc trudno tym bardziej. Generalnie lista pozytywna kiedy UŻYĆ jest dość krótka.

    1. zmienna volatile 'auto' we wnętrzu funkcji nie ma sensu (za wyjątkiem tricków, zawsze jakiś da się podać kontrprzykład). Zarówno funkcji z wątku "main", jak i z przerwań. Wynika to samego rozwinięcia kodu (trzeba podłubać lub umieć sobie wyobrazić). Tak, być może ma sens do statycznych (linki na dole). volatile pointer też nie widzę sensu, bo jaki (może da się taki pokazać)? Skoro pointer nie istniał przed wejściem do funkcji, to tym bardziej nie istniała kopia wskazywanej zmiennej (edit ... ups.. chyba da się podać kontrprzykład)

    2. konwersja typów w 99.9% jest "wporzo" od typu szerszego do węższego bez rzutowania (rygorystów językowych proszę o skorygowanie słówka). Odrzucasz C++, ale analiza const metoda() const w różnych wariantach jest intelektualnie rozwijająca.
    Da się podstawić pod volatile z 'nie-volatile' (z nie-const do const) itd... to skrótowo tyle o "niestosowności rzutowania". Źle zrzutować da się wszystko na wszystko.

    3. Nie znamy sposobu użycia wnętrza struktury. Generalnie słowo nie oznacza atomowości, tylko propagowanie volatile na każdą ze składowych, ROZUMIANYCH JAKO ODDZIELNY ATOM. Pierwsze pole z chwili t1, drugie pole z chwili t2. Prawie zawsze nie o to chodzi.
    Z braku orientacji JAK chcesz używać WNĘTRZA struktury uchylam się od własnego kodu.

    4. pewnego rodzaju "obietnica" volatile w ścisłym sensie odnosi się do jednej operacji jednego integera nie większego od sig_atomic_t. Co do jakiejkolwiek większej danej (oraz np inkrementów) powinniśmy sie kłócić o synchronizację, a nie volatile.

    https://en.wikipedia.org/wiki/Volatile_(computer_programming) (polecam angielską wersję, polska spłyca)
    http://en.cppreference.com/w/c/language/volatile
  • #17
    MrKsawery
    Level 13  
    Napisałem więcej punktów więc może pomieszałem.
    W tej strukturze będą znajdować się bufory w formie tablicy 100 bajtów, oraz spora ilość flag pomiędzy wątkiem głównym a przerwaniami i różne zmienne pomocnicze.

    Taki sposób jak zaprezentowałem ma pewną zaletę: łatwo debagować, bo w dowolnym momencie mogę podejrzeć całą strukturę, wszystkie bufory itd.

    Sprawdzałem kod w asemblerze, bez volatile byłoby słabo - mowa o flagach irq-wątek. Pewnie optymalniej będzie nadać volatile flagą wewnątrz struktury a nie całej. I to wszystko po to by ominąć niekorzystną optymalizację

    Co do synchronizacji na razie nie potrzeba nic i wszystko bardzo dobrze działa, ale dla bezpieczeństwa zastosuję chyba taki algorytm:

    - dane którą są obrabiane w wątku będą pobierane na samym początku i przepisywane do lokalnych zmiennych na stos - mam gwarancję że gdy nastąpi wywłaszczenie to nic się nie stanie.

    Wyłączanie przerwań jakoś dla mnie nie przemawia, bo jeśli jest to transmisja i coś umknie to nie będzie dobrze. Takie pytanie czy jak wyłączę przerwanie i w tej chwili coś się wydarzy np przepełnienie licznika zostanie ustawiona flaga przerwania ale go nie wywoła, więc jak je włączę to to przerwanie zostanie wywołane czy nie?

    Co do C++ nie mówię nie, ale stosowałbyś na AVR typu ATmega8 lub mały STM32F0? Sam kiedyś coś robiłem w c++ i wydawał się przyjemniejszy od C.
  • #18
    JacekCz
    Level 39  
    MrKsawery wrote:

    Co do synchronizacji na razie nie potrzeba nic i wszystko bardzo dobrze działa, ale dla bezpieczeństwa zastosuję chyba taki algorytm:

    - dane którą są obrabiane w wątku będą pobierane na samym początku i przepisywane do lokalnych zmiennych na stos - mam gwarancję że gdy nastąpi wywłaszczenie to nic się nie stanie.

    Wyłączanie przerwań jakoś dla mnie nie przemawia, bo jeśli jest to transmisja i coś umknie to nie będzie dobrze. Takie pytanie czy jak wyłączę przerwanie i w tej chwili coś się wydarzy np przepełnienie licznika zostanie ustawiona flaga przerwania ale go nie wywoła, więc jak je włączę to to przerwanie zostanie wywołane czy nie?


    Wyłączanie przerwań w wersji "dla kumatych" jest oczywiście bardzo krótkie, NAJWAŻNIEJSZE aby mieć bronione wejścia w sekcje krytyczne. Mowa o wymiarze 2-5 rozkazów maszynowych. Jak nie robisz video w czasie rzeczywistym, nie ma problemu, niczego nie zgubisz.

    Nie znam i nie wyobrażam sobie systemu przerwań innego niż taki, o jakim mówisz.
    najsłabsze proce chyba mogą tak obsłużyć jedno (zgubić dopiero drugie)





    MrKsawery wrote:

    Co do C++ nie mówię nie, ale stosowałbyś na AVR typu ATmega8 ...

    A dokładnie, dokładnie, szkoda że nie mam więcej ósemek :)
    Skontaktuję się na priv w/s źródeł.

    Program testowy przezwany z C na C++ zwiększył się o DWA BAJTY segmentu danych, rychło mi "oddał" to w kodzie. Jak "powziął informację" o enkapsulacji pól mógł agresywniej optymalizować (zgodnie z moją intencją). O komforcie, bezpieczeństwie nie wspominam.
    Zagadnienie: generowanie dźwięku (kluczowany sinus, Morse, te sprawy, maksymalnie możliwy przyjemny dla ucha) na przerwaniach. Od pierwszej kompilacji chodził bez zwiechy, choć charczał (nieregularność czasu ticków ze względu na nieidentyczną ilość taktów arytmetyki potem ulepszone).
    Mam na myśli nie moją genialność, tylko enkapsulację "warstwy niższej" (IRQ/zasilanie kolejki zdarzeń z klucza) i "wyższej" (konsumowanie kolejki). Bardzo się w tym bezpiecznie developowało.
  • #19
    MrKsawery
    Level 13  
    Nie rozumiem czegoś: pisałeś mi że niepotrzebnie robię wskaźnik volatile, a na stronie do której podałeś linka jest potwierdzenie tego co pisałem:
    Quote:
    Any attempt to read or write to an object whose type is volatile-qualified through a non-volatile lvalue results in undefined behavior:
    Code: c
    Log in, to see the code



    Przecież to identyczny przykład. I dalej to o czym mówiłem:
    Quote:

    p = vp; // Error: discards qualifiers (volatile int to int)
    p = (int*)vp; // OK: cast
  • #20
    JacekCz
    Level 39  
    MrKsawery wrote:
    Nie rozumiem czegoś: pisałeś mi że niepotrzebnie robię wskaźnik volatile, a na stronie do której podałeś linka jest potwierdzenie tego co pisałem:
    ....

    Przecież to identyczny przykład. I dalej to o czym mówiłem:
    ...


    Mój stosunek do języka jest w rodzaju "praktyk" a nie "teoretyk". Nie przywołam z głowy sformułowań standardu.
    Nie będę przedłużaj dyskusji o kodzie (świadomie) akademickim (a przykład ilustruje w gruncie rzeczy sytuację "negatywną") , nie znam się głęboko, nie jest dla mnie użyteczny itd.

    pozdrówka