Silv

  1. Warszawa
Programista (front-end) bez większego doświadczenia. — Pisywałem wiersze i opowiadania.
Silv
2020-03-19 23:44

W App Store oraz Google Play dostępna jest aplikacja "Kwarantanna domowa". Dokładny opis aplikacji oraz regulamin korzystania znajdują się na stronie: https://www.gov.pl/web/koronawirus/kwarantanna-domowa Cytując:

Program umożliwia potwierdzenie miejsca, w którym przebywasz, podstawową ocenę stanu zdrowia i bezpośrednie zgłoszenie zagrożenia. Ułatwia też zaopatrzenie w najpotrzebniejsze artykuły osobom, które nie mają takiej możliwości samodzielnie.

#aplikacja #kwarantanna #koronawirus #Polska

Anna Lisik

Przydatne. Dzięki. Wytestuje bankowo :)

cmd

Fajna totalitarna aplikacja, chińczyki dają 5 gwiazdek. Ludzie którzy pracowali przy jej stworzeniu powinni co rano pluć w lustro.

danek

@cmd: lepiej żeby chore osoby biegały po mieście?

TomRiddle

@danek: dychotimia, argument niemerytoryczny.

danek

tylko ta aplikacja nawet nie jest obowiązkowa, a ma pewnie odciążyć policje więc to raczej dobrze

cerrato

@danek: tak... super apka do pokazywania, gdzie leży mój telefon ;) Bardzo miarodajne wyniki, nie ma co :D

danek

nie tylko do tego ;) ale to trzeba przeczytać najpierw co się komentuje :p

LukeJL

jak jesteś w domu, to i tak rząd wie, gdzie leży twój telefon, jeśli ma twój adres zamieszkania. Chyba, że chcesz udawać, że robisz kwarantannę.

Akihito

@cerrato: a widzisz nie czytasz i się mylisz. Appka generalnie polega na tym, że co jakiś czas prosi cię o selfie i masz na to 20 minut w przypadku braku reakcji panowie mundurowi wiedzą, że powinni sprawdzić czy wszystko z tobą ok i grzecznie w domu siedzisz ;)

Tonyu

Duża waga aplikacji, 40 MB.

Manna5

A co jeśli wyślesz nie swoje zdjęcie?

Akihito

@Manna5: to ta osoba musi robic wszystkie selfie za ciebie ;)

Manna5

Przeczytałem jeszcze, że śledzi lokalizację. Na szczęście w Narzędziach Programisty Androida jest opcja symulowania konkretnej lokalizacji we wszelkich aplikacjach.

Silv

@Manna5: czemu w przypadku kwarantanny "na szczęście"?

Silv

@Anna Lisik: poczekam na komentarz @Manna5, zanim (jeśli) to skomentuję.

Anna Lisik

@Silv: no to owocnego czekania....... jest piątek wieczór.

danek

@Anna Lisik: i co z tego, nie ma gdzie siedzieć w piątekowy wieczór :P

KamilAdam

Piątek wieczór, wreszcie można w spokoju całą noc poprogramować lub napisać zaległe teksty na bloga ^^

Anna Lisik

@danek: @Kamil Żabiński udzielił wyczerpującej odpowiedzi na Twoje pytanie :)

Manna5

Poza tym, to trochę dziwna aplikacja, bo jak policja ma w ten sposób pilnować osoby zamknięte w kwarantannie, to co jak ta osoba nie ma smartfona (albo ma, tylko na Symbianie).

Silv

@Manna5: ale czemu "na szczęście"?

Tonyu

Na razie oceny w Google Play bardzo słabe (komentarze wskazują na problemy techniczne a nie na ideę aplikacji że np inwigilacja). Komentarze na fb również https://m.facebook.com/story.[...]977&anchor_composer=false

Tonyu

I powstała apka robiąca "to samo" z otwartymi źródłami.

https://www.guaana.com/challe[...]Ngi6Ns/uRjwAqyuPgaSja7dH/main

"The government has launched an app to unburden police forces. Although the idea of the app is great, its ratings are very poor. Our research showed users have no real incentive to use it and feel a sense of invigilation. Why is our app better? Because we want people to enjoy the app!"

Silv
2020-03-19 18:30

Firma IT.focus stworzyła aplikację IHELPYOU.app, która pomaga połączyć wolontariuszy z potrzebującymi podczas obecnej pandemii. Chodzi np. o robienie zakupów, wyprowadzenie psa, gdy ktoś nie może / boi się wyjść z domu. Jest to ułatwione m.in. dzięki lokalizowaniu osób na mapie.

Obecnie najwięcej osób zarejestrowało się z Polski, ale autorzy mają nadzieję, że rejestrować będą się ludzie w całej Europie.

Aplikacja ruszyła 16 marca 2020.

#aplikacja #online #wolontariat #potrzebujący #pomoc #koronawirus #IT.focus

czysteskarpety

Pytanie czy wolontariusze mają niezbędne środki i wiedzę do takiej pomocy, inaczej sami poprzez taki kontakt mogą roznosić wirusa.

Tomek Pycia

@czysteskarpety: myślę, że na tyle trąbią na około o tym jak zachować ostrożność, że średnio rozgarnięty człowiek wie jak to zrobić.

enedil

@Tomek Pycia: no, póki co metodą jest nie spotykać się z ludźmi, a w takiej pomocy spotykanie ludzi (nawet jeśli z odległości dwóch metrów) jest kluczowe.

Tomek Pycia

@enedil: no tak, to niech zdychają z głodu ci, co po zakupy wyjść nie mogą.

Silv
2020-02-08 19:14

Wpadłem właśnie na jeden sposób, jak szybko zdecydować, czy refaktoryzacja we własnym kodzie jest potrzebna. Jeśli IDE sygnalizuje błąd w linii X, ty przechodzisz do linii X i myślisz sobie: "Ej, nie lubię tego fragmentu kodu…", to znaczy, że refaktoryzacja jest potrzebna. :P

Piszę: we własnym kodzie, bo jedni wykorzystują jedne praktyki, a inni inne. Kod pisany według innych praktyk niż nasze refaktoryzacji wymagać nie musi, ale podobać się nam też nie musi.

#kod #refaktoryzacja #podejmowanie-decyzji #błędy #porady #uczucie

cerrato

Takie rozszerzenie - IDE nie musi błędu zgłaszać. Równie dobrze może to dotyczyć sytuacji, w której po prostu po czasie zaglądasz w działający kod i czujesz odrazę połączoną z zażenowaniem i WTF'em.

LukeJL

dla mnie (w sytuacjach wątpliwych) miarą jest raczej to, czy umiem się poruszać po danym kodzie. Kod może brzydki, ale jeśli umiem się po nim zgrabnie poruszać, to pół biedy. Jeśli zaś nie potrafię czegoś znaleźć we własnym kodzie, ew. wkurza mnie, że muszę latać po kilku miejscach w kodzie, żeby zmienić jedną rzecz - to wtedy jest to sygnał do refaktoru. Poza tym czasem refaktor jest wymuszony tym, co chcę zrobić (np. dodać jakąś nową opcję do programu), wtedy muszę zrobić ten refaktor, żeby iść dalej. Chociaż czasem owszem jest tak, że "nie lubię tego fragmentu kodu" albo "czuję, że ten kod jest nieelegancki i łamie zasady dobrego projektowania". Wtedy refaktoring prewencyjny, żeby nie narobić zbyt dużego długu technicznego.

LukeJL

Czyli podsumowując - refaktoring robię po to, żeby zwiększyć własną produktywność.

superdurszlak

@cerrato: wrócę do swojego kodu po tygodniu, czuję odrazę. Spojrzę nań po przerwie na kawę - też czuję odrazę. Nawet w trakcie pisania czuję odrazę, i w trakcie refaktoringu i tuż po też, bo ciągle mi siedzi z tyłu głowy że da się napisać lepiej tylko nie umiem tego zrobić. Kiedy mam przestać refaktorować? :P

cerrato

@superdurszlak: to moze zamiast wiecznych poprawek naucz się pisać porzadnie. A potem, jak już temat ogarniesz, to chętnie się do ciebie zgłoszę na korepetycje ;)

LukeJL

Potem się refaktoruje na kolejnych poziomach. Najpierw to są drobne rzeczy typu "dodam spację po przecinku, bo tak będzie ładniej", potem jest już "wydzielę ten kod do osobnej funkcji, żeby pozbyć się duplikacji", potem robi się gorąco "architektura jest zła, przerobię te moduły, żeby lepiej współpracowały ze sobą i żeby każdy kolejny lepiej współpracował", a na końcu jest "przepiszę ten cały projekt od nowa, bo widzę, ile rzeczy źle robiłem" (czyli Ostateczny Refaktoring).

superdurszlak

@cerrato: czego Jaś się nie nauczył, tego Jan nie będzie umiał :(

cerrato

Czyli mówisz, że już nie ma dla mnie nadziei? Szkoda :(

Silv

@LukeJL: tak to właśnie jest. :) — @cerrato: dla każdego jest nadzieja. W czasie, gdy @superdurszlak będzie się uczyć dobrych praktyk kodowania, ja Cię mogę podszkolić z filozofowania na wszelkie tematy związane z kodem. :)

superdurszlak

@cerrato: żeby tylko, chyba też przespałem trzeci trymestr :/

Silv
2020-01-07 16:28

To się aż kwalifikuje na osobny wpis.

(Moich ostatnich przygód z językiem C ciąg dalszy).

Ostatnio dość często mam okazję spotykać zachowanie kodu, które mnie dziwi. Wczoraj napotkałem taką nierówność:

-1 > 0

Czekaj, od początku: jak to się stało?

Zaczęło się to tak, że (tu dużo kodu) porównywałem sobie dwie zmienne.

W tym miejscu należy zaznaczyć, że mogłbym pokazać rzeczywisty kod, ale uznałem, że nie ma sensu – m.in. wpis straciłby na wyrazistości. Przygotowałem jego wersję uproszczoną. Przyjmijmy, że najważniejsze zmienne mają nazwy start, end oraz str.

Porównanie wyglądało tak:

for (/* coś tam */) {
    // Zmieniaj zmienną "end"
    if (end >= start) {
        // Ustawiaj zmienną "str"
    }
    // Zmieniaj zmienne "start" oraz "end"
}

Z kodu byłem zadowolony, bo przeglądałem go sto dużo razy. Niczego w sumie nie brakowało… tylko program ustawiał zmienną "str" w pewnych przypadkach, kiedy tego od niego nie oczekiwałem. Niektóre obroty pętli ustawiały ją – te, które powinny (poprawnie), niektóre nie – te, które nie powinny (znów poprawnie), a jeszcze inne ustawiały ją właśnie wtedy, kiedy nie powinny (a to źle).

Dla przyspieszenia i ułatwienia debugowania wybrałem sobie jeden przypadek do sprawdzania. Porównując program sto pierwszy kolejny raz linijka po linijce oszacowałem, że wartości zmiennych powinny w nim wynosić 0 oraz -1. Wypisanie zwróciło właśnie tak:

for (/* coś tam */) {
    // Zmieniaj zmienną "end"
    if (end >= start) {
        // Ustawiaj zmienną "str"
        printf("start == %ld, end == %ld\n", start, end); // start == 0, end == -1
    }
    // Zmieniaj zmienne "start" oraz "end"

Co uważniejsi mogli już zauważyć pewną rzecz, której ja od razu nie zauważyłem; jedną z najważniejszych rzeczy; na razie jednak przejdę do tego, co z tym wtedy zrobiłem…

Z samego faktu, że program wypisywał te dwie zmienne, można wnioskować, że 0 >= -1. W tym momencie przypomina się aż tekst Radosta ze "Ślubów panieńskich" Fredry:

Oszalał!

No… albo znany mem z Jackiem Chanem, jeśli nie znacie tak dobrze "Ślubów".

Próbowałem wziąć to na logikę. "Nie może być – myślałem – żebym przy zdrowych zmysłach widział takie rzeczy".

Nauczony doświadczeniem z językiem C i własnym kodem, sprawdziłem – może ja porównuję wskaźniki? Nie, zmienne nie zostały zadeklarowane jako wskaźniki. To nie to.

Przy tak prostym kodzie niewiele zostało do sprawdzenia. W porywie bezradności wypisałem bezpośrednio porównanie. Program zadowolony z siebie zwrócił 1…

for (/* coś tam */) {
    // Zmieniaj zmienną "end"
    if (end >= start) {
        // Ustawiaj zmienną "str"
        printf("start == %ld, end == %ld, end >= start == %d\n", start, end, end >= start); // start == 0, end == -1, end >= start == 1
    }
    // Zmieniaj zmienne "start" oraz "end"

Kombinowałem: może 1 nie oznacza "prawdy" w C? Może tylko czasami? Wszak (przykładowo) w Bashu 1 zazwyczaj oznacza "fałsz", a 0 – "prawdę".

Nie. C reference mówi wyraźnie:

The type of any relational operator expression is int, and its value (which is not an lvalue) is 1 when the specified relationship holds true and ​0​ when the specified relationship does not hold.

Zacząłem niemal powtarzać za Radostem:

Ja go nie odmienię, / To rzecz daremna.

(Mowa oczywiście o zachowaniu mojego kodu, a nie środowiska uruchomieniowego języka C).

Bo i cóż mogłem zrobić? (W sumie dużo, ale to pytanie retoryczne, no). Zrezygnowany sprawdziłem jeszcze, której relacji (z dwóch obecnych w operatorze >=) dotyczył wynik. Zrobiłem to w celu uzyskania jakichkolwiek dalszych informacji do debugowania – promyk nadziei na rozwiązanie sprawy w przyszłości. Całe szczęście wynik dotyczył relacji nierówności…

Zaświtała mi w głowie dziwna myśl, żeby spojrzeć na deklaracje tych zmiennych… Po co, przecież wszystko już obejrzałem tysiąc wiele razy… Ale spojrzałem:

size_t start = 0;
size_t end = start - 1;

"Zaliczyłem" gest Patricka Stewarta

Hm, nadal nie rozumiem.

Już wyjaśniam. Z mojej strony w powyższym kodzie są trzy sprawy całkiem niepoprawne:

  1. Zainicjalizowałem zmienną o typie size_t wartością ujemną. Jak wiadomo, typ size_t jest typem o atrybucie unsigned, czyli nie przyjmuje wartości ujemnych. Jak mówi specyfikacja:

    size_t is the unsigned integer type of the result of sizeof , _Alignof (since C11) and offsetof, depending on the data model.

  2. Nie dość tego: byłem na tyle bezczelny, by sprawdzać, czy rzeczywiście zmienna o tym typie ma wartość ujemną.

  3. Moja bezczelność sięgnęła szczytu, kiedy na końcu nie tylko chciałem, by miała ona wartość ujemną; nie tylko ją sprawdzałem; ale kazałem funkcji printf wyświetlić jej wartość jak zmienną o typie z atrybutem signed – za pomocą formatu %ld.

    Parafrazując Radosta:

    Gwałtu! Co ten hultaj robi!

    Ale kto by tam czytał specyfikację przed pisaniem kodu…

Najpewniej byłem świadomy, że typ size_t jest unsigned; jednak wprowadziłem go dopiero w czasie debugowania (gdy ogólnie zmieniałem typy zmiennych w całym kodzie na bardziej "logiczne"). Na początku rzeczywiście był typ int – i to pewnie utrwaliło mi się w głowie. Obecnie jestem zdania, że po prostu zapomniałem o konsekwencjach tej zmiany.

Natomiast gdybym nie popełnił błędu w punkcie nr 3, być może od razu bym się zorientował, że coś jest nie tak. printf mogłaby wypisać coś podobnego do tego (to wynik z ideone.com dla GCC 8.3 oraz C99):

size_t a = -1;
printf("%lu", a); // 18446744073709551615

I tu już wyraźnie widać, że coś jest nie tak.

Tym kończąc…

Czekaj, czekaj. Powiedz w końcu, czemu właściwie -1 > 0 dla zmiennych unsigned?

Wyjaśnię dla trybu kompilacji C99; co prawda, przy kompilacji tego skryptu używam jego modyfikacji GNU99, ale nie mogłem nigdzie znaleźć wystarczających informacji na temat tej modyfikacji, by na nich polegać.

Nie jestem doświadczony w języku C. Z tego, co zrozumiałem z dokumentacji, zachodzi tutaj konwersja typu o atrybucie signed na typ o atrybucie unsigned. Jest to potwierdzone np. przez tę odpowiedź na Stack Overflow. Konwersja zachodzi najpewniej w sposób opisany w tej odpowiedzi na Stack Overflow. Nie jestem jednak przekonany, czy w ogóle to rozumiem, ponieważ według tej odpowiedzi zmienna start musiałaby mieć wartość ULONG_MAX + 1, a ideone.com dla kompilatora GCC 8.3 i trybu C99 pokazuje (o ile dobrze to sprawdzam), że zmienna ma wartość ULONG_MAX:

size_t a = -1;
printf("%ld\n", a);             // -1
printf("%lu\n", a);             // 18446744073709551615
printf("%lu\n", ULONG_MAX);     // 18446744073709551615
printf("%lu\n", ULONG_MAX + 1); // 0

Być może nie rozumiem reguł przeliczania wartości na typy w języku C…

…Jest więc czego się uczyć. :)

Linki

Linki do specyfikacji niektórych części języka i bibliotek – tak dla kompletności informacji:

#c #język-programowania #błędy #bugi #debugowanie #c99 #gnu99 #konwersja #facepalm #śluby-panieńskie #cytaty #nie-tak-to-łatwo-jak-się-zdaje

Wibowit

I między innymi dlatego Java nie ma typów unsigned :]

xxx_xx_x

Tak jak napisał @UczonyHumanista, nie ma tu nic dziwnego tak sie koduje liczby binarne. Od typu zależy czy najstarszy bit jest znakiem czy liczbą i tyle...

xxx_xx_x

@Wibowit: Ale jak np potrzebujesz dokladnie 32 bitowego typu unsigned to sie robi problem i trzeba pokombinować, no ale cos za cos

lion137

Jakbyś jak człowiek uzył debugera, a nie "print debuging" :), to odrazu Byś widział co się dzieje.

vpiotr

W C/C++ taka nierownosc moze byc jednoczesnie prawdą i fałszem dla tych samych danych wejsciowych w tym samym programie - ze wzgledu na UB kompilator moze zrobic rozne ciekawe rzeczy z IF-ami. Dlatego END dobrze jest deklarowac jako "indeks elementu bezposrednio ZA ostatnim rozpatrywanym elementem".

cerrato

A z Pascala, który ma możliwość włączenia pilnowania zakresów zmiennych ludzie się śmieją :P

Silv

@UczonyHumanista: w zasadzie nie mam czasu – ale przypomnę sobie o tym! Dodałem do zakładek. — @lion137: toż przecież używam. Ale ten GDB w wierszu polecenia toporny jest trochę. A pod VS Code nie umiem go skonfigurować. Więc najszybciej i najprościej… — @vpiotr: ale jakie tu widzisz UB? A co do indeksu: też nad tym myślałem. Ale doszedłem do wniosku, że w zasadzie nie będzie większych różnic, więc wybrałem wersję bardziej dla mnie logiczną.

Silv

A, flagi kompilatora. Dzięki.

Maciej Cąderek

zmienna start musiałaby mieć wartość ULONG_MAX + 1 - tego nie rozumiem, przecież ma, twoje start to 0, ULONG_MAX + 1 też daje zero.

Silv

@Maciej Cąderek: teraz jak spojrzałem, to w ogóle pomieszałem – zmienna nie ma przypisywanej wartości ULONG_MAX + 1, tylko taż wartość jest dodawana do aktualnej wartości zmiennej…

vpiotr

@Silv masz racje, to jednak nie UB, ale w tym jednym IFie IMHO masz kilka bledow stylistycznych utrudniajacych czytanie:

  • "end" zmieniane w petli, moze nie znam kontekstu ale tego bym unikal
  • "end" w porownaniu przed "start" - Yoda conditions Ty lubisz?
  • ">=" zamiast nierownosci ostrej moze sugerowac ze cos tu wybuchnie
alagner

@Silv napisz w gdb - [ENTER]. Ctrl-p Ctrl-n kontroluja wtedy historie, strzalki scrolluja kod

TomRiddle

@vpiotr: A a >= b to nie jest pod spodem ! a<b? Więc czemu miałoby wybuchnąć.

vpiotr

@TomRiddle: Pod spodem to AFAIK asm x86 ma osobne instrukcje na kazda nierownosc, to raczej kwestia czytelnosci i "maintability". Trudno mi to wytlumaczyc, moze to kwestia popularnego "off by one", moze wlasnie tego czy end oznacza ostatni element.

student pro

Zig to fajny język, pewnie wykryłby to w momencie kompilacji, a jeśli nie to wywaliłby się w runtime (to jeszcze zależy od trybu kompilacji). Jeśli świadomie chce się wykonać operację arytmetyczną z zawinięciem, to trzeba dodać symbol %, np. start = end -% 1

KamilAdam

Mnie to w ogóle nie dziwi. Zderzyłem się z tym na studiach, gdzie kazali nam programować dziwne mikroprocesory w dziwnym C, w którym domyślnie int był bez znaku. Już pierwsza napisana pętla zamieniła się w nieskończoną, bo źle iterowaliśmy :D

vpiotr

@Kamil Żabiński: a nie chodzilo czasem o char? O domyslym unsigned int pierwszy raz slysze, ale mozliwe. Moze prowadzacy Was trolowal i zmuszal do pisania signed int jakąś dziwną opcją w makefile.

KamilAdam

@vpiotr Niestety nie pamiętam co to były za mikrokontrolery, może jakieś stare PIC. Chociaż o nich znalazłem tylko informacje, że kompilator ma flagę -k, która powoduje, że unsigned jest domyślny. Niestety kompilatory C dla mikrokontrolerów często łamały standard

alagner

@Kamil Żabiński: PIC to jest do programowania w C taka padaka, że paaaanie. Mnie z tej architektury najbardziej zapadła w pamięć zmienna short long oznaczająca 24 bajtowego inta :D proszę https://www.microchip.com/forums/m738383.aspx

Silv

@vpiotr: 1) "end" zmieniane w petli, moze nie znam kontekstu ale tego bym unikal – nie znasz kontekstu, ale nie sądzę, by był taki ważny; cóż złego w tym? 2) "end" w porownaniu przed "start" - Yoda conditions Ty lubisz?Yoda conditions :D; rzeczywiście, mnie też wydaje się to nieintuicyjne, patrząc na same nazwy; ale patrząc na to, że to end się zmienia, a nie start, to już idzie za intuicją. 3) ">=" zamiast nierownosci ostrej moze sugerowac ze cos tu wybuchnie – nie rozumiem. — @alagner: poczytam o tym. — @student pro: dzięki za nowy język. :) Nie nauczę się go pewnie, ale dobrze znać możliwości.

Silv

PS. @vpiotr: w sumie start też się zmienia, ale end zmienia się częściej. Sam nie wiem. Ważniejsza jest jakby zmiana end dla mnie. Sam nie wiem. Dla mnie to było bardziej intuicyjne.

no_solution_found

debugger Twoim przyjacielem :)

Silv

@no_solution_found: mam wrażenie, że bardziej produktywne mi wychodzi "printf debugging" niż "gdb-CLI debugging". :/

alagner

@Silv to obczaj jak dziala gdb-tui albo zaprzęgnij jakieś IDĘ do roboty.

Silv

@alagner: jak pisałem wyżej, nie umiem skonfigurować GDB pod Visual Studio. Mając doświadczenia z nieudaną konfiguracją oszacowałem, że szybciej będzie wyświetlać komunikaty na ekranie znanym sposobem, niż bawić się z opcjami konfiguracyjnymi…

Silv

PS. Może to niezbyt przyszłościowe podejście, ale za cel moich wysiłków postawiłem sobie działający skrypt, a nie działający debugger.

lion137

Nie Masz wyjścia. Musisz skonfigurować i zacząć używać debuger. Spróbuj CodeLite - w nim debuger działa "od kopa":)

Silv

@lion137: jak jeszcze zacznę szukać nowego oprogramowania i uczyć się je konfigurować, to dopiero cel "działający skrypt" odejdzie w przyszłość. ;)

alagner

QtCreator albo Eclipse i wszystko od kopa lata.

Silv

Hm, może rzeczywiście powinienem zobaczyć Eclipse. Już kiedyś używałem…

xxx_xx_x

Jak nie przeszkadza ci kupno IDE to może CLion?

Silv

@xxx_xx_x: wpisałem "cn ide" w dwóch wyszukiwarkach, ale nic ciekawego nie znalazłem. Dzięki, wiesz, oczywiście wolałbym darmowe, ale tak czy siak nie o to chodzi. Mam po prostu dosyć zużywania energii na szukanie, pobieranie oraz konfigurowanie zamiast na faktyczną pracę. To jest fajne, nie przeczę; lubię, jak coś działa – niezależnie co to jest; ale działające IDE to nie jest mój cel. Dlatego napisałem, że pomyślę o Eclipse, którego używałem.

xxx_xx_x

Autokorekta mi podmienila nazwę, poprawiłem. Chodziło o CLion od jetbrains

Silv

Ach, autokorekta, w porządku. (Czemu jej nikt nie wyłącza?)

xxx_xx_x

Zwykle przyspiesza pisanie, ale czasami potrafi namieszać

Azarien

@vpiotr: Pod spodem to AFAIK asm x86 ma osobne instrukcje na kazda nierownosc - czytelny asm tak, ale kod maszynowy już nie. instrukcja ja (jump if above) to jest dokładnie ta sama instrukcja co jnbe (jump if not below or equal)

Silv
2020-01-05 23:30

Odczytując raporty Valgrinda* z kodu napisanego w C, mam ochotę czasem powiedzieć w ten sam deseń co Jan Kobuszewski w skeczu "Ucz się, Jasiu": "Jak Ty się tu źle kopiujesz, no jak Ty się tu źle kopiujesz!"…

(kilka minut sprawdzania kodu)

…"A może rzeczywiście źle".


* Valgrind – narzędzie używane m.in. do sprawdzania wycieków pamięci w kodzie.

#c #valgrind #pamięć #zarządzanie-pamięcią #jan-kobuszewski #ucz-się-jasiu #kabaret #nie-tak-to-łatwo-jak-się-zdaje

Silv
2020-01-04 18:12

Przypadkiem trafiłem na ciekawostkę z języka C. Nagłówek funkcji strstr w man 3 strstr wygląda tak:

char *strstr(const char *haystack, const char *needle);

…Mnie się takie podejście do programowania nawet podoba. :)


PS. Dla nieznających C – funkcja strstr wyszukuje ciąg znaków w drugim ciągu znaków.

grski

nazwa funkcji kompletnie nic mi nie mówiła, przeczytałem nazwy arugmentów i żaróweczka się zapaliła, nice!

Silv

Jak cel funkcji da się odczytać z nazw argumentów, to chyba znaczy, że są intuicyjne. ;) Inna sprawa, jak będą to czytać osoby, które w swoim ojczystym języku nie mają igieł w sianie…

Azarien

tylko co za genjusz wymyślił taką nazwę dla funkcji.

Silv

Rozsądne pytanie. Ja się przyzwyczaiłem. Odczytuję to jako "[search for a ]str[ in a ]str".

Silv
2020-01-01 14:51

Wczoraj skończyłem pisać mój skrypt w języku C, który przetworzył mi plik tekstowy zawierający ponad 4,5 miliona linii i stworzył ok. 20 tys. plików wynikowych.

UPDATE: Tutaj siedzi on sobie na GitHubie: https://github.com/silvuss/silvuss-detlan

Nic skomplikowanego; ot, skrypt wyszukuje linie spełniające podany warunek i kopiuje je do poszczególnych plików wynikowych.

Wydajność

Czas wykonywania głównej pętli: ok. 30 sekund. Uważam to za wynik świetny, porównując z moim poprzednim skryptem, w Bashu, który zamierzał robić to samo kilka godzin (przerwałem mu w połowie). (Pamiętajcie, że na Bashu mogę nie znać się za dobrze. Żeby właściwie porównać te języki, znajdźcie benchmarki inne niż moje skrypty :P).

Poprawność wyjścia

Nie jestem doświadczony w języku C; wyszło, że taki nieskomplikowany skrypt to nic trudnego… powiedzmy. Wydaje się działać.

Właśnie. Ktoś mógłby zapytać, czy skrypt działa poprawnie. Przeglądałeś wszystkie pliki wynikowe linijka po linijce? Skąd wiesz, że jakiś znak występujący 3 razy na krzyż w pliku wejściowym nie został pominięty, ponieważ wśród 10 użytych funkcji użyłeś akurat jednej, która nie obsługuje odpowiedniego kodowania?

Słuszne uwagi. Nie wymagam wielkiej poprawności na tym etapie, więc przygotowałem sobie prosty jednolinijkowiec w Bashu, by sprawdzić poprawność plików:

for file in ./* ; do if [[ $(grep -o "here-i-typed-the-text-to-search-for" $file | wc -l) != 1 ]] ; then echo "$file is NOT OK" ; fi ; done

Wykonawszy ten test na plikach wynikowych, nie otrzymałem żadnego wyjścia (i tego właśnie oczekiwałem). — Przy okazji, jeśli oko Cię lekko zakuło od spojrzenia na konstrukcję for file in ./*, to ja nie wiem, w ilu wypadkach jest bezpieczna (na pewno nie we wszystkich!). Niemniej, ciekawostka, Greg mówi, że jest w porządku: http://mywiki.wooledge.org/Pa[...]les_or_doing_stuff_with_files A jeśli chcesz pisać lepsze skrypty w systemach *nix, moim zdaniem warto także przeczytać ten "esej" Davida A. Wheelera (m.in. pisze o tej konstrukcji; wyszukaj w tekście in ./* lub in *).

W razie czego (w miarę potrzeb) przygotuję sobie coś więcej.

Spostrzeżenia

W związku ze skończeniem pisania mojego skryptu mam kilka spostrzeżeń.

Makefile

Do kompilacji nie użyłem makefile; wystarczyła mi historia poleceń linii komend. Nie wiem, czy to źle, czy dobrze. Do poprzedniego programu w C użyłem makefile. (Nie wspominam tego miło. Ale to pewnie dlatego, że nie chciało mi się wtedy uczyć tego języka. Wystarczyło mi do szczęścia samo przypominanie sobie C od podstaw).

Wersja standardu / dialektu C

Pisząc w C dobrze być pewnym, którego standardu / dialektu się używa, nadto – jawnie powiedzieć to kompilatorowi. Ot, bo różnorodność ich jest. Szczególnie jak jawnie używa się więcej niż jednej flagi kompilatora.

Alokacja pamięci

Mam dziwne wrażenie, że alokując pamięć w funkcjach i zwracając sam wskaźnik do niej, można by zrobić to lepiej – jakoś lepiej. Przecież to podatne na błędy (=dziwne) pisać przy każdej funkcji: "Uważaj: jeśli używasz tej funkcji, nie zapomnij zwolnić pamięci". A jak inaczej zasygnalizować użytkownikowi?

A używać funkcji, które operują na już zaalokowanej pamięci? To znów dla mnie nieintuicyjne. Nie napiszę przecież (choć w skrypcie napisałem):

const char *src = "Wesoły tekst o niczym";
const char *dst = malloc(strlen(src) + 1); // pamiętać: +1 to na kończący NULL
strcpy(src, dst);
free(dst);

tylko raczej wolę:

const char *src = "Wesoły tekst o niczym";
const char *dst = strdup(src); // przed C20 dostępne w dialektach GNU

choć oczywiście w tym drugim przypadku muszę tak samo na koniec:

free(dst);

(@alagner, dziękuję jeszcze raz).

Nie żebym* chciał wymyślać koło i implementować rozwiązanie pokroju garbage collectora, ale…


* To nie jest przytyk do nikogo. Po prostu mnie samemu ciężko zapamiętać wszystkie reguły, i tutaj bym zrobił błąd interpunkcyjny, gdybym nie sprawdził.

Wyjątki

Przydałaby się obsługa wyjątków czy czegoś… Ogólnie: przejrzysty mechanizm obsługi błędów, niezależny od "logiki biznesowej". ( :P )

Do tej pory nie zauważyłem, by w C była jedna wartość, którą można zwrócić z funkcji o każdym typie, a dzięki temu można uznać za odpowiednik wyjątku.

Są co prawda inne sposoby…

Trzeba się ich nauczyć. Może nawet czasem lepsze niż wyjątki?

Szkoda, że nie trafiłem na jakąś stronę, która listuje, a najlepiej porównuje wszystkie możliwe sposoby.

Postscripta

(Dla zainteresowanych moją działalnością na naszym forum).

  • @tajny_agent, pamiętam o wskazówce dot. prealokowania pamięci – może zrobię to w kolejnym skrypcie.
  • Nie, nie zapomniałem o Angularze… Często mi się przypomina, jak wchodzę na forum. Ale co zrobić? Są różne projety; czas płynie; jedne pomysły znikają, inne się pojawiają; nie, żebym się usprawiedliwiał… Krótko mówiąc, jeśli zdecyduję się wrócić do Angulara lub definitywnie zakończyć obecną przygodę z nim, to wyraźnie o tym napiszę (podkreślam, że obecną, bo co przyszłość przyniesie, tego nie wiem).
  • Nie, nie zapomniałem o CoyoteNET… Patrz wyżej. Jeśli zdecyduję się wrócić, to wyraźnie o tym napiszę. Na razie, jak napisałem na Slacku, wciąż robię to, co zaplanowałem jeszcze przed pojawieniem się pomysłu na CoyoteNET.

#c #skrypt #przetwarzanie-tekstu #text-processing #bash #język-programowania #spostrzeżenia


UPDATE: Dodałem link do GitHuba.

alagner

Nie ma za co, polecam się na przyszłość :). PS: linki dot. błędów nie działają

alagner

BTW, zamiast iterować po plikach i grepować pojedynczo mogłeś zlliczyć linijki samym grepem a potem jeszcze jakoś to przepuścić przez filtr (nie wiem czy AWK u mnie nie będzie u mnie nadmiarowy) grep -c ”regex” * | awk 'BEGIN {FS=":"} {if ($2 != 1) print $1 " incorrect"}'

lion137

Globalnych dużo widzę zmiennych, kod trudny do debugowania i analizy znaczy. Jak się boisz o poprawność to Otestuj to porządnie.

enedil
int silvLinesCount(FILE *const fp)
{
    if (fp == NULL)
    {
        fprintf(stderr, "Error: silvLinesCount: fp == NULL");
    }

i co, jak masz NULLa, to szczęśliwie idziesz dalej, nie przejmując się tym?

Silv

@alagner: oczywiście, że nie działają… Nigdy jeszcze nie dawałem wielokropka po linku – widać, że parser czyta wielokropek jako jego część. :) Poprawione. A ta sugestia – w sumie racja, ale obecnie mam cały czas podejście "wystarczy, że działa (w rozsądnym czasie)". — @lion137: ogólnie jestem wielkim fanem testowania; ale nie, nie teraz. — @enedil: nom; założyłem, że sposób, w jaki ten skrypt wywołuję (i debuguję), skutecznie umożliwi wykrycie błędów, niezależnie jak szczegółowa będzie ich obsługa. Celna uwaga zresztą, ciekaw byłem, czy ktoś to zauważy. W następnych skryptach chciałbym obsługiwać coś więcej niż happy path.

Silv

Generalnie mówiąc, takiego wpisu nie popełniłbym wcześniej, ale obecnie zmieniam spojrzenie na blogowanie. Być może warto pisać przemyślenia w bardziej surowej formie niż np. na moim blogu na GitHubie. Przynajmniej mają szansę w ogóle ujrzeć światło dzienne.

lion137

"ogólnie jestem wielkim fanem testowania; ale nie, nie teraz." ??? Piszesz kawałek kodu, Zamykasz go w funkcję i Testujesz, ktoś inaczej podchodzi do programowania?

Silv

@lion137: miałem na myśli: testowania formalnego, specjalnie przygotowanymi testami jednostkowymi itd. Obecnie testowanie przebiegało tak, że uruchamiałem program; działał – to działał.

lion137

Uuuu, to nie tak, jak Piszesz funkcję, to od razu Staraj się ją ubić i Testuj; tak Dostaniesz kod, w miarę poprawny

Silv

Hm, skąd te wielkie litery na niektórych czasownikach? ;) Też ze Star Wars? Dobrze, wiesz co, poczekaj na drugi skrypt, będzie otestowany.

lion137

Ha, ha, czy ja tu coś nie kumam? W polskim, pisząc, w drugiej osobie, dajemy dużą literę? TAK/NIE, czy to już odeszło?

Silv

Yyy… Ale… w zaimkach, nie czasownikach…

alagner

tak jeszcze na Twój kod sporzjałem... po co we free robisz cast do char*?

Silv

@alagner: ponieważ to jest zgodne z sygnaturą free; interesuje mnie niewyświetlanie żadnych ostrzeżeń przez kompilator, nawet tych "najmniej istotnych".

alagner

@Silv to jest to mocno dziwne imho. Jaka wersja gcc i czy to gcc czy g++?

Silv

Nie wiem, czy odwiedzałeś folder /docs na GitHubie – tam napisałem, jak kompilowałem: gcc -g -lm -Wall -std=gnu99 -Wextra -Wpedantic -Wmissing-prototypes -Wold-style-definition [script-name]

Silv

PS. GCC 9.2.1 20190827 (Red Hat 9.2.1-1) (GCC)

Silv

Co mnie trochę przy tym denerwuje, to że -Wall nie znaczy all.

Silv

PS. Świadomie wybrałem takie opcje. Jeśli kiedyś uznam, że warto, przeczytam całą man gcc i być może dojdzie wyświetlanie jeszcze jakichś ostrzeżeń.

alagner

Dziwne masz to free, problem jest pewnie gdzie indziej...
https://linux.die.net/man/3/free
Godboltem sprawdziłem teraz Twoje switche i nie generuje warningów.
(5 minut później) no już jasne gdzie jest problem.
const char *const actualStart a potem free(actualStart). Więcej constów nie mieli?;P no ale na logikę. Wskaźnik pokazuje na stałą. W embedded np. w pamięci flash. Read-only. Jak to chcesz zdealokować?
Taki masz warning: warning: passing argument 1 of 'free' discards 'const' qualifier from pointer target type?

Silv

@alagner: nie jestem pewien, czy free jest dziwne. W man pod podanym przez Ciebie linkiem jest void free(void *ptr) i o to chodzi. Być może mógłbym rzutować z void zamiast z char – ale że nie wiedziałem, jaką miałoby robić to różnicę, to wybrałem opcję, która była moim zdaniem bardziej logiczna semantycznie. — Tak, takie mam ostrzeżenie.

alagner

@Silv błąd masz nie w wywołaniu free, tylko typie wskaźnika. const char* const x to jest stały wskaźnik na stałą typu char. To skoro ten wskaźnik pokazuje STAŁĄ, to jakim prawem w ogóle chcesz ją zwalniać? Po co tyle tych constów tam nawaliłeś? Warning mówi dokładnie o tym - "ten wskaźnik pokazuje stałą, zwolnienie obiektu docelowego to zignorowanie jego stałości".

alagner

@Silv www.cdecl.org Twoim przyjacielem. Możliwe, że Fedora też ma cdecla wywoływanego z CLI, ale głowy nie dam.

Silv

Wiesz co, zgadzam się, że nie jest dobrą praktyką używać konstrukcji, co do których nie ma się pewności, czy są potrzebne. Z drugiej strony uważam, że jeszcze gorszą praktyką jest zakładanie, że coś nie ma miejsca, a nie sprawdzenie tego. Bezpieczniejsze wydało mi się nadmiarowe użycie instrukcji funkcji free niż nie użycie, gdy będzie potrzebna. Chętnie usunę zwalnianie pamięci dla stałych, tylko muszę być pewien, co się dzieje z pamięcią w przypadku stałych. Masz jakieś źródło?

Silv

PS. Ach, jeszcze pytasz o to, czemu tak dużo const. Moim zdaniem to słowo kluczowe, którego nadmiar w większości wypadków może pomóc wykryć błędy. Dlatego też używam tam, gdzie oszacowałem, że będzie logiczne.

alagner

Wróć. To nie jest problemem, że Ty zaalokowaną pamięć chcesz zwolnić, problemem jest, że oznaczasz ją - fałszywie - jako stałą.
silvSubstr alokuje. I masz to zwolnić. Ale przypisanie jej wyniku do const char* const x jest błędem.

Silv

Czekaj… muszę to sprawdzić.

Silv

Rzeczywiście, jest pewna niespójność. Czyli nigdy nie powinienem oznaczać wartości takiej zmiennej, która wskazuje na pamięć zaalokowaną przez malloc, jako stałej? Czy też coś innego masz na myśli?

alagner

Zasadniczo to mam na myśli. To "nigdy" to z dokładnością do jakichś kosmicznych zastosowań na dziwnych architekturach/platformach, kiedy już będziesz wiedział co robisz.

Silv

@alagner: OK. Ale nie rozumiem. W moim rozumieniu języków programowania – albo coś jest polecane w przypadku "A" i tego używasz, albo jest w tym przypadku niepolecane i tego nie używasz. Czemu w tym przypadku tego nie polecasz?

Silv

PS. Tzn. inaczej: czy tę wyżej opisaną niekonsekwencję (która może być myląca) można jakoś usunąć lub ew. obejść? Czy też są z takim oznaczaniem jeszcze inne problemy?

alagner

Const jest polecany do przekazywania argumentów do funkcji przez wskaźnik/referencję (w C++), bo informuje wyraźnie, że funkcja go nie zmodyfikuje i zagwarantuje to kompilator. Ale deklarowanie dynamicznie alokowanej pamięci jako stałej w całym czasie jej życia jest imho niekonsekwencją programisty.

Silv

Ogólnie ja to widzę tak: jeśli nigdy nie zamierzam zmieniać danej wartości, oznaczam ją jako stałą. Kropka. Nadto, jeśli nigdy nie zamierzam zmieniać danego wskaźnika, oznaczam go jako stały. Kropka. Stąd czasem wychodzi const char *const. Co jest złego w informowaniu, że oczekuje się, że zaalokowana pamięć nie będzie zmieniana?

alagner

Fakt, że ją alokujesz implikuje, że ją zwolnisz. Czyli zmienisz.

Silv

Chyba już widzę… chodzi Ci o to, że funkcja alokująca pamięć musi uznać, że będzie ona zmieniana, natomiast funkcja ją wywołująca jakby dodaje nowe ograniczenie, mówiąc: "ta pamięć może i była zmieniana w funkcji, którą wywołałam, ale u mnie już nie będzie zmieniana". Moim zdaniem wymaga to, oczywiście, pewnego zastanowienia, ale nadal jest bardziej intuicyjne niż nie oznaczenie const. Widzisz, dla mnie deklaracja zmiennej bez const dla jej wartości oznacza, że można jej wartość modyfikować.

Silv

PS. Oczywiście nie "usuwa", a dodaje ograniczenie.

alagner

Krótko: malloc zwraca Ci wskaźnik na pamięć modyfikowalną. Ty zmieniasz typ wskaźnika na wskaźnik na pamięć stałą. Free stałej zwolnić nie może, bo zwolnienie = oddanie systemowi do potencjalnie wpisania tam czegoś innego.

Silv

Rozumiem i zgadzam się, i taka jest moja intencja. Używam const jedynie w celu oznaczenia, że oczekuje się, że coś nie będzie modyfikowane. Nie używam tego w celu oznaczenia, że coś nigdy nie było modyfikowane. Kiedyś może i było, w przyszłości może będzie, ale dopóki wyraźnie nie powiem (nie użyję np. rzutowania (char *)), to wartość musi być const. Tak to widzę. Nieintuicyjnie?

Silv

Jeszcze inaczej powiem: dla mnie wszystkie deklaracje powinny być const domyślnie. Powinno się specjalnie oznaczać jedynie te sytuacje, w których coś ma być zmieniane. A że w C jest odwrotnie, to staram się jakoś patchworkować moją filozofię.

alagner

@Silv nie chcę uchodzić za wyrocznię ale imho to jest zła praktyka w C. Czym innym jest funkcja przyjmująca wskaźnik na stałą, czym innym to.
Teraz wobraź sobie, że masz const char* const x = strdup("abc"); /*cośtam cośtam*/free((char*) x); a potem zmieniasz to na const char* const x = "abc"; /*cośtam cośtam*/free((char*) x); i dostajesz core dumpa na twarz w dziwnym momencie.
Generalnie w C/C++ większym grzechem jest usunięcie consta niż jego brak. Z uwagi na utrzymywalność kodu.

Silv

Wiesz, pomyślę jeszcze nad tym. Na razie idę pisać drugi skrypt.

Silv

Dzięki za zauważenie tej niespójności tego niedopatrzenia w moim rozumowaniu.

alagner

BTW. Polecam dołożyć sobie jeszcze warning (niestety nie zauważyłem, żeby w Twoich był, ale może to przeoczenie...) -Wwrite-strings i zobacz co się stanie jak zrobisz char* x = "abc"; vs const char* x = "abc";. Wtedy to wszystko nabierze sensu więcej sensu. I lektura na dobranoc do poduszki
https://stackoverflow.com/que[...]ring-literals-not-to-be-const
https://stackoverflow.com/que[...]onstant-variables-stored-in-c

alagner

Po namyśle: C++ byłby rozwiązaniem jeśli chodzi o bardziej intuicyjnego consta; minimalna obiektowość już mogłaby wiele dać.. W uproszczeniu: póki nie operujesz ręcznie na pamięci, consta możesz użyć bardziej jako "logicznego" aniżeli "fizycznego" (const std::string foo {"bar"} i po bólu, mimo, że może leżeć na stercie, implementacja stringa po sobie posprząta, a obiektu nie zmodyfikujesz). Tylko znowu: jeśli użyjesz gdzieś const_cast bo kompilator krzyczał, to najpewniej robisz to źle. No ale o tym już rozmawialiśmy i jeżeli chcesz nauczyć się C to oczywiście nie ma co zmieniać języka.

Mirai

@alagner o co chodzi z tą nazwo foo, dla wszystkich przykładów z c++? Co nie wezmę jakąkolwiek książkę lub poradnik na internecie, wszędzie wszyscy tak nazywają te przykłady.

alagner

@Mirai nie tylko c++. Tak się przyjęło po prostu.

Mirai

@alagner tak samo za zmienną iterującą w pętli. Czemu akurat jest zawsze i ? Czemu nie np. x, a, c albo jakakolwiek inna litera?

alagner

Strzał trochę na oślep: bo w pętli i-terujesz.

Silv

@Mirai: mnie też czasem uderza, że coś jest po prostu konwencją – nie ma tego w żadnym standardzie. Mając do czynienia z tak ustrukturyzowaną wiedzą jak specyfikacje języków programowania, chciałoby się, by wszystko było opisane.

Silv
2019-12-30 00:59

Przed chwilą pierwszy raz użyłem CLI debuggera gdb i zainstalowałem paczkę debuginfo w systemie. W tym wpisie chciałem się tylko podzielić z Wami radością, że poznałem właśnie coś nowego, i że to działa.

Otrzymałem m.in. taki komunikat:
warning: Loadable section ".note.gnu.property" outside of ELF segments

(Jeszcze) Nie wiem, co on oznacza, ale… jej, jak ja lubię poznawać nowe rzeczy, żeby je zrozumieć. :)

#fedora #debugowanie #dbg #debuginfo #oprogramowanie #linux #cli

PerlMonk

A to ja wiem, tam jest napisane o seksji loda. Bardziej poważnie: debugowanie fajna sprawa, można dowiedzieć się o swoim kodzie ciekawych rzeczy :D .

Silv

Być może jeszcze nie mam doświadczenia, jeśli chodzi o zaawansowane debugowanie, ale wolałbym, żeby nie ujawniało nie musiało ujawniać żadnych informacji o moim programie poza exited with status 0. ;)

msm

Na pewno chodzi o CLI debugger dbg a nie gdb? 🤔

Silv

@msm: no przecież, że GDB! :) Mój błąd. Poprawione.

msm

Tak podejrzewałem, ale fajne typo bo łatwo przeoczyć (nazwa dgb też by nieźle pasowała do debuggera :P)

somedev

Do gdb to polecam ddd a najlepiej z Eclipse. Obecnie cli gdb to masochizm i celowe obniżanie swojej produktywności ;) Sto lat temu tego się nauczyłem na laboratoriach z Architektury Komputerów i po nich nigdy nie musząc nie użyłem wersji CLI. O ile edytor w cli ma sens tak debugger źle się obsługuje.

Silv

@somedev: rzeczywiście, trochę nieintuicyjne narzędzie w stosunku do debugowania w IDE z prawdziwego zdarzenia. Ale i tak wyobrażam sobie, że o wiele lepiej jest debugować z GDB niż bez niczego. ;) Chciałbym wykorzystać VS Code, ale szczerze, nie chce mi się naprawiać błędów… GDB już mi działa i tyle.