eGospodarka.pl
eGospodarka.pl poleca

eGospodarka.plGrupypl.misc.elektronikaZagwozdka w C Keil. › Re: Zagwozdka w C Keil - wyjaśnienie.
  • Data: 2019-02-14 13:59:28
    Temat: Re: Zagwozdka w C Keil - wyjaśnienie.
    Od: q...@t...no1 (Queequeg) szukaj wiadomości tego autora
    [ pokaż wszystkie nagłówki ]

    J.F. <j...@p...onet.pl> wrote:

    >>Ale co kompilator może zrobić, jak sam procesor nie obsługuje
    >>atomicznego dostępu do tej zmiennej (bo np. jest 8-bitowy, a zmienna
    >>16-bitowa)?
    >
    > To samo, co programista ma zrobic :-)

    Programista ma kontekst, którego nie ma kompilator. Programista wie, kiedy
    chce mieć sekcję krytyczną (która nie musi obejmować wyłącznie atomicznego
    dostępu do zmiennej szerszej niż magistrala adresowa).

    >>Zmienna może się zmienić między każdą z tych instrukcji.
    >
    > Cos w tym jest.

    Jest jest... po to są sekcje krytyczne.

    >>Czemu? Co ma do tego ARM? Chodzi o szerokość magistrali danych? To
    >>rozwiązuje tylko jeden problem,
    >
    > Tak, problemu z int nie bedzie :-)

    Z odczytem int nie, ale np. z read-modify-write już tak.

    >>ale inne (chociażby ten pierwszy przykład wyżej) pozostają.
    >
    > Ciezkie jest zycie programisty.

    A to swoją drogą... ale raczej przez ludzi a nie przez komputery :)

    Trzeba po prostu pamiętać, że (przynajmniej w przypadku C i C++)
    kompilator nie tłumaczy kodu na język maszynowy jeden do jednego. Kod to
    tylko pewien abstrakcyjny opis, który kompilator może traktować z dosyć
    dużą dowolnością. Dochodzą do tego chociażby zagadnienia związane z
    reorderingiem.

    Przykładowo:

    https://www.nongnu.org/avr-libc/user-manual/optimiza
    tion.html

    1. Dzielimy (powolna operacja)
    2. Wyłączamy przerwania cli
    3. Zapisujemy wynik dzielenia do zmiennej (szybka operacja)
    4. Włączamy przerwania

    A optymalizator twierdzi, że wyłączy sobie przerwania przed dzieleniem, bo
    tak mu mnieszy kod wychodzi :)

    Gdy zagłębimy się w optymalizowanie "undefined behavior", to robi się
    jeszcze ciekawiej. Przykładowo:

    #v+
    void fn(int *p)
    {
    int a = *p; // martwy kod
    if (p == 0) return; // nadmiarowe sprawdzenie
    *p = 1;
    }
    #v-

    Spodziewalibyśmy się, że `if (p == 0) return;` nie zostanie usunięte, ale
    ponieważ programista wcześniej dokonał dereferencji, a dereferencja null
    pointera jest UB, to kompilator może usunąć ten drugi, nadmiarowy test bo
    zakłada, że nie ma UB (czyli że p nie może być 0). Moje gcc nie usuwa, bo
    najpierw usuwa martwy kod, ale wcale nie musi -- inna wersja lub inny
    kompilator może zachowywać się inaczej i najpierw usunąć nadmiarowe
    sprawdzenie, a dopiero potem martwy kod.

    Kolejny przykład.

    #v+
    #include <limits.h>
    #include <stdio.h>

    int fn(int i)
    {
    if (i + 1 > i)
    printf("Nie ma integer overflow\n");
    else
    printf("Uwaga: integer overflow\n");
    }

    int main(void)
    {
    fn(INT_MAX);
    return 0;
    }
    #v-

    Kompilujemy z -O0, dostajemy wynik, że jest integer overflow. Kompilujemy
    z -O2, optymalizator stwierdza, że przepełnienie typu ze znakiem jest UB,
    więc usuwa nam ten warunek (ustawia go na true).

    > I co sie dziwic, ze MS w C# zrobil stringi niemodyfikowalne ...

    W C# pisałem coś tylko raz i tylko dlatego, że musiałem :) Zupełnie nie
    moja działka.

    --
    Eksperymentalnie: http://facebook.com/groups/pl.misc.elektronika

Podziel się

Poleć ten post znajomemu poleć

Wydrukuj ten post drukuj


Następne wpisy z tego wątku

Najnowsze wątki z tej grupy


Najnowsze wątki

Szukaj w grupach

Eksperci egospodarka.pl

1 1 1

Wpisz nazwę miasta, dla którego chcesz znaleźć jednostkę ZUS.

Wzory dokumentów

Bezpłatne wzory dokumentów i formularzy.
Wyszukaj i pobierz za darmo: