Ta strona używa ciasteczek (plików cookies), dzięki którym może działać lepiej. Dowiedz się więcejRozumiem i akceptuję

[Programowanie] Pułapki języka C

Autor Wiadomość
GAndaLF 



Posty: 293
Pomógł: 6 razy
Otrzymał 69 piw(a)
Programuję w:
C, ASM
Należę do:
SKALP
Wysłany: 29-09-2013, 02:55   [Programowanie] Pułapki języka C

W poprzednim artykule postawiłem tezę, że dobry programista powinien wiedzieć jakie aspekty języka są niebezpieczne i umiejętnie sobie z nimi radzić. Najlepszym rozwiązaniem jest jasne wyrażanie swoich intencji i unikanie podejrzanych konstrukcji. Teraz postaram się przybliżyć kilka niebezpiecznych sytuacji. Niektóre będą oczywiste, albo wręcz śmieszne, inne z kolei mogą dotyczyć aspektów z których wiele osób nie zdaje sobie spawy. Mam nadzieję, że pozwoli to czytelnikowi wyrobić sobie odpowiedni instynkt pozwalający wykrywać potencjalnie niebezpieczne miejsca na bieżąco w trakcie pracy nad kodem.

UWAGA, to tylko wstęp!
Dalsza część artykułu dostępna jest na darmowym blogu Forbota.

Kliknij, aby przeczytać całość!


Poniżej znajdują się komentarze naszych użytkowników powiązane z tym artykułem.

Popularny artykuł » Tworzenie aplikacji Android - #1 - Wstęp




bug.jpg
Plik ściągnięto 279 raz(y) 50.64 KB


Walczę jak lew, padam jak mucha

Micromouse Legend
ucgosu.pl - blog o programowaniu embedded i robotyce. Tematyka bardziej dla zaawansowanych.
Postaw piwo autorowi tego posta
 
 
Więcej szczegółów
Wystawiono 1 piw(a):
other019
Marooned 




Posty: 769
Pomógł: 9 razy
Otrzymał 72 piw(a)
Skąd: Poznań
Programuję w:
C
Wysłany: 30-09-2013, 14:59   



Dorzucę, że styl
Kod programu: Zaznacz cały
if ()
{
...
}

ma ten minus, że przy operacjach kopiuj/wklej można sobie coś wstrzyknąć pomiędzy if a {. Dlatego o wiele bezpieczniejszym i spójnym jest formatowanie typu:
Kod programu: Zaznacz cały
if () {
...
}


Polecam również zawsze dodawać {} nawet jeśli ma to być prosty kod w stylu:
Kod programu: Zaznacz cały
if (a==b) {
a++;
}


Dzięki temu przy modyfikacji kodu albo wstawianiu instrukcji debugujących nie ma ryzyka takiego błędu:
Kod programu: Zaznacz cały
if (a==b)
log(a);
a++;


Tu wcześniejsze ciało instrukcji if wypada nam poza warunek.
Wyjątkiem mogą być jednolinijkowce:
Kod programu: Zaznacz cały
if (a==b) a++;

ale ich też się zazwyczaj unika.


"In the brave new world of the year 2000, a kiss can still break your heart." - Program from Cirque du Soleil's Alegría

Nad tymi gwiazdami jest wszechświat szybujących potworów! Wiedziałaś?
Postaw piwo autorowi tego posta
 
 
OldSkull 




Posty: 1327
Pomógł: 44 razy
Otrzymał 76 piw(a)
Skąd: Poznań/Leszno
Programuję w:
C/C++
Należę do:
CybAiR
Moje roboty:
Skynet, Cuprum, Oldskull+, Marchewa+

Wysłany: 30-09-2013, 16:05   

Marooned napisał/a:
ma ten minus, że przy operacjach kopiuj/wklej można sobie coś wstrzyknąć pomiędzy if a {. Dlatego o wiele bezpieczniejszym i spójnym jest formatowanie typu:

Kod programu: Zaznacz całyif () {

...

}

Zmniejsza to jednak przejrzystość i czytelność kodu. A mimo wszystko ciężko przy kopiuj-wklej coś popsuć jeśli się kopiuje cały blok kodu.

Czasami jest też tak, że pewne czynności obniżają czytelność kodu, przykładowo co oznacza taka kontrukcja:

Kod programu: Zaznacz cały
if(a<--b)
{
...
}

Jak to pierwszy raz zobaczyłem, to zacząłem szukać informacji co robi operator strzałki :D


Aktualnie pracuję nad: dwukołowy schodopokonywacz.
Postępy prac(wstrzymane): mechanika:<10%, elektronika:<1%, dokumentacja:<1%, program:0%, opis: 0%.
Postaw piwo autorowi tego posta
 
 
GAndaLF 



Posty: 293
Pomógł: 6 razy
Otrzymał 69 piw(a)
Programuję w:
C, ASM
Należę do:
SKALP
Wysłany: 30-09-2013, 19:18   

Marooned: Specjalnie unikałem jasnego deklarowania że jeden styl nawiasów {} jest poprawny a inny nie. W poprzednim temacie OldSkull udzielił kompletnie odwrotnej porady. Obie koncepcje mają sporo zwolenników i dla każdego z nich wybranie drugiej jest kompletnie niezrozumiałe. Dlatego nie chciałem rozpisywać się na ten temat żeby uniknąć sporu, którego nie da się rozwiązać.

Osobiście jestem zdania, że styl K&R czyli nawias początkowy w tej samej linii co wcześniejsze wyrażenie, jest zupełnie nieczytelny. Znalezienie nawiasu początkowego w bardziej rozbudowanym kodzie jest dla mnie niesamowicie trudne. Dlatego przychylam się do zdania OldSkulla.

Zasadą dotyczącą stylu nawiasów, której bezwzględnie należy przestrzegać jest dostosowanie się do stylu projektu. Jeżeli dołączamy do jakiegoś projektu w późniejszym czasie albo nasz styl zostanie przegłosowany przez innych musimy zacisnąć zęby i się dostosować.

Warto przeczytać » Sprawdzone sposoby na zasilanie mikrokontrolera



Walczę jak lew, padam jak mucha

Micromouse Legend
ucgosu.pl - blog o programowaniu embedded i robotyce. Tematyka bardziej dla zaawansowanych.
Postaw piwo autorowi tego posta
 
 
Villentre 



Posty: 30
Pomógł: 4 razy
Otrzymał 1 piw(a)
Skąd: ~Kraków
Programuję w:
C/C++
Wysłany: 01-10-2013, 03:19   

Co do stylu i czytelności (więc może lekko offtopując) powiem tak:

Jak dla mnie mniejszą różnicę w czytelności robi to czy klamra jest w tej samej czy w osobnej linii niż rozmiar tabulacji. Tab na 4 spacje (taki standardowy) nie umywa się do takiego na 6 czy 8 (takich używam) spacji.

Przy monitorze 19" i szerokości 1400px takie wcięcie zbytnio pola nie ogranicza, a jest widoczne...


"Zielony... Zielony nowicjusz pomaga nowicjuszowi..."
Postaw piwo autorowi tego posta
 
 
 
Marooned 




Posty: 769
Pomógł: 9 razy
Otrzymał 72 piw(a)
Skąd: Poznań
Programuję w:
C
Wysłany: 01-10-2013, 12:01   

OldSkull napisał/a:
Zmniejsza to jednak przejrzystość i czytelność kodu.
To ciekawe, bo dla mnie zwiększa :)
Tak, to jest dyskusja o wyższości świąt bożego narodzenia nad świętami wielkiej nocy.

A co do tego, że ciężej odnaleźć nawias otwierający... sęk w tym, że nie ma potrzeby jego odszukania jeśli mamy prawidłowe wcięcia. Poza tym, nawet najprostsze notatniki podświetlają pasujące nawiasy, więc tu też problem niejako znika nawet przy braku jakiegokolwiek formatowania.

Podsumowując. Nie pisałem (choć tak uważam), że ten format jest lepszy. Zaznaczyłem tylko, że eliminuje on pewne ryzyko zniszczenia kodu (i więcej kodu widać na ekranie - szczególnie, że nowe monitory mają coraz gorsze proporcje i mało px w pionie). I to nawet nie moja opinia, ale oficjalny plus tej notacji - kiedyś czytałem dość spory artykuł na temat różnych typów formatowań i teraz dzielę się tym z Wami :)


"In the brave new world of the year 2000, a kiss can still break your heart." - Program from Cirque du Soleil's Alegría

Nad tymi gwiazdami jest wszechświat szybujących potworów! Wiedziałaś?
Postaw piwo autorowi tego posta
 
 
osmial 



Posty: 15
Pomógł: 1 raz
Skąd: Piotrków Trybunalski
Programuję w:
c,asm
Wysłany: 22-11-2013, 20:24   

Możliwe, że sie czepiam ale widzę ten temat któryś tam już raz i za każdym razem rośnie mi ciśnienie ;) Dlaczego? Po pierwsze tytuł jak z onetu mający na celu moim zdaniem nabicie kliknięć w link, a zawartość... jest kontynuacją tytułu. O co mi chodzi? Mianowicie o przedstawienie elementów języka jako czegoś co zostało wprowadzone nie po to aby służyć programiście ale na złość jemu.

Cytat:
To jest tylko kilka przykładowych tricków. Możliwe jest tworzenie w ten sposób naprawdę ciekawych konstrukcji. Oczywiście pod żadnym pozorem nie można wykorzystywać ich w poważnych programach.


Na przykład taki cytat (zdań w tym sensie jest wiele w tym wpisie). Autor traktuje czytelnika jak przygłupa który ma w każdym kolejnym podpunkcie wpajane, że język C powstał po to by utrudnić mu życie... tylko mam takie jedno pytanie, dlaczego coś takiego miało by nie być stosowane ? Dopuki programista świadomie korzysta z języka moim zdaniem nie ma się czego obawiać. Nie ma w tym wpisie prawdopodobnie żadnej ukrytej funkcjonalności języka nie opisanej przez standard, jeśli więc standard coś przewiduje to jaki sens ma pisać o pułapkach ? Pułapka to coś nieznanego, co może faktycznie wymagać sprecyzowania :)

A coś takiego:
Cytat:
Może się wydawać, że zmienne a i b powinny przyjąć taką samą wartość. W końcu struktura składa się z 3 bajtów, więc wyrażenia są jednoznaczne. W wielu procesorach np. ARM lub x86 struktury są jednak wyrównywane do jakiejś wartości np. 32bity albo 64bity. W takim wypadku rozmiar struktury będzie większy niż suma rozmiarów wszystkich jej elementów.


To już na prawdę zagrywka na poziomie onetu :) To nie struktury są złe. Po pierwsze można w kompilatorze wyłączyć wyrównywanie, po drugie jest to jak najbardziej porządana funkcjonalność.

Postaw piwo autorowi tego posta
 
 
GAndaLF 



Posty: 293
Pomógł: 6 razy
Otrzymał 69 piw(a)
Programuję w:
C, ASM
Należę do:
SKALP
Wysłany: 23-11-2013, 04:45   

Jeżeli tworzysz kod wykorzystujący nieoczywiste funkcjonalności języka, każesz czytelnikowi domyślać się intencji. Oczywiście zakładasz, że ludzie, z którymi współpracujesz znają język, w którym piszecie. Po jakimś czasie pewnie nawet przyzwyczajają się do cudzych nawyków. Jednak za każdym razem, kiedy czytają taką linijkę kodu muszą tracić czas na przetworzenie informacji. Czasem mogą patrzeć na szybko i coś źle zrozumieć.

Bardzo często programiści głowią się, jak upchnąć kod w jak najmniejszej liczbie linii, najlepiej jeszcze stosując różne opisane przeze mnie zabiegi, żeby pokazać jak dobrze znają język. Celem artykułu było pokazanie, że takie postępowanie jest krótkowzroczne. Jeżeli uważasz, że kod który piszesz jest przydatny i istnieje szansa, że będziesz go wykorzystywał później, udostępniał innym osobom itd nie możesz postępować w ten sposób. Czas, który tracisz podczas debugowania, dodawania nowych funkcjonalności, jakichkolwiek innych zmian, czy nawet tłumaczenia innym o co ci chodziło jest dużo większy niż ta chwila, którą poświęcisz na przemyślenie, przejrzystą implementację i dodanie komentarzy.


Walczę jak lew, padam jak mucha

Micromouse Legend
ucgosu.pl - blog o programowaniu embedded i robotyce. Tematyka bardziej dla zaawansowanych.
Postaw piwo autorowi tego posta
 
 
Więcej szczegółów
Wystawiono 1 piw(a):
Mechano
osmial 



Posty: 15
Pomógł: 1 raz
Skąd: Piotrków Trybunalski
Programuję w:
c,asm
Wysłany: 25-11-2013, 23:03   

Każda funkcjonalność jest nieoczywista jeżeli nie posiadamy wystarczającej wiedzy na jej temat. Ludzie natomiast nie muszą przyzwyczajać się do czyichś nawyków, ponieważ głupotą było by takie podejście w firmach w których ciągle występują zmiany w zespołach i tak naprawdę nigdy nie doszło by do poznania nawyków wszystkich pracowników, dlatego istnieje coś takiego jak zasady kodowania (tutaj odnośnie tego samego podrozdziału w artykule) które obowiązują w firmie i których trzymać się mają pracownicy.
Co do reszty artykułu to tak jak powiedziałem, jeśli ktoś pisze świadomie w swoim języku, stara się rozumieć co gada do niego kompilator, korzysta z narzędzi kontrolujących jakość kodu, wycieki pamięci etc. wtedy artykuł tego typu można wsadzić między bajki. Oczywiście rozumiem, że chciałeś podzielić się wiedzą i jest to słuszne ale szczerze radzę abyś w przyszłości pisał artykuły w innym tonie bo takie jak ten są podwaliną forumowych mitów, a nie to pewnie było Twoją intencją. C jak każdy język ma swoje specyficzne funkcjonalności, nie jest też najprostszy i nie jest idioto odporny ale żaden nie jest. Może natomiast być piekielnie efektywny, a ceną za to są jak to nazwałeś 'pułapki', zdefiniowane przez standard z resztą :)

Postaw piwo autorowi tego posta
 
 
mactro 




Posty: 723
Pomógł: 33 razy
Otrzymał 50 piw(a)
Skąd: Kutno/Poznań
Programuję w:
C/Arduino
Wysłany: 26-11-2013, 10:15   

osmial, to, że można zroić
Kod programu: Zaznacz cały
#define true rand()%2

nie znaczy, że się powinno. W zdecydowanej większości zastosowań wystarczy, że kod jest zwyczajnie efektywny, piekielnie już być nie musi. A skoro tak, to i różnych diabelskich sztuczek nie trzeba stosować.

To, że jesteś w stanie napisać świetnie działający program, który będziesz doskonale rozumiał, nie znaczy, że inni nie będą mieli z tym problemu. Nie uważam się za złego programistę, ale perspektywa przerabiania czyjegoś kodu zawsze wywołuje we mnie nieprzyjemne dreszcze.


www.trobot.pl - sklep dla robotyków - zestawy, podwozia, czujniki, silniki, mechanika.
Postaw piwo autorowi tego posta
 
 
 
osmial 



Posty: 15
Pomógł: 1 raz
Skąd: Piotrków Trybunalski
Programuję w:
c,asm
Wysłany: 26-11-2013, 12:15   

Jasne, tylko pisanie w artykule np.:
Kod programu: Zaznacz cały
while (*s != 0);
{
    s++;
}

i zaznaczanie, że jest to pułapka języka jest IMO złym nastawieniem autora, bo to najzwyklejszy błąd w kodzie, a to czy kompilator zwrócu warning czy nie to kwestia kompilatora i ewnetualnie nad tym można się rozwodzić.
Chodzi mi o to, że język sam w sobie nie powinien być rozpatrywany w kontekście tego czy ma pułapki czy nie jeśli te zachowania przewiduje dokumentacja analogicznie w innym języku można stworzyć analogiczną konstrukcję do ww. i czy ona tez będzie pułapką języka? Nie, będzie to błąd programisty.

Postaw piwo autorowi tego posta
 
 
OldSkull 




Posty: 1327
Pomógł: 44 razy
Otrzymał 76 piw(a)
Skąd: Poznań/Leszno
Programuję w:
C/C++
Należę do:
CybAiR
Moje roboty:
Skynet, Cuprum, Oldskull+, Marchewa+

Wysłany: 26-11-2013, 14:05   

BTW: zrobienie while (*s != 0); wcale nie musi być błędem, powiem wręcz, że tego się używa w mikrokontrolerach wręcz na okrągło, tylko *s jest jakimś makrem. Zwykłe czekanie aż zmieni się stan rejestru procesora (np. pojawi się jakaś flaga) to jest właśnie taki zapis! Tutaj nam podpowiada, że jest to błąd to, że {} jest w kolejnej linii mimo iż nei jest potrzebne.


Aktualnie pracuję nad: dwukołowy schodopokonywacz.
Postępy prac(wstrzymane): mechanika:<10%, elektronika:<1%, dokumentacja:<1%, program:0%, opis: 0%.
Postaw piwo autorowi tego posta
 
 
osmial 



Posty: 15
Pomógł: 1 raz
Skąd: Piotrków Trybunalski
Programuję w:
c,asm
Wysłany: 26-11-2013, 14:55   

OldSkull, pisząc, że jest to błąd miałem na myśli ten konkretny przykład gdzie ten średnik zmienia logikę dzialania programu. Zastosowanie while(warunek); jest jak piszesz stosowane nagminnie, szczególnie w pracy z mikrokontrolerami. Nie zgodzę się jednak, że otwarcie nowego bloku jest błędem. W mojej wersji gcc: gcc version 4.4.7 20120313 (Red Hat 4.4.7-3) (GCC) taki kod:
Kod programu: Zaznacz cały
while(1);
   {
     int i = 0;
   }

kompilowany z flagą -Wall nie daje nawet warningów.

Tutaj: http://devpytania.pl/ques...ukcja-sterujaca troszeczke więcej na ten temat. Jest też zaproponowane kilka ciekawych zastosowań tej opcji:)

Ostatnio zmieniony przez osmial 26-11-2013, 14:56, w całości zmieniany 1 raz  
Postaw piwo autorowi tego posta
 
 
GAndaLF 



Posty: 293
Pomógł: 6 razy
Otrzymał 69 piw(a)
Programuję w:
C, ASM
Należę do:
SKALP
Wysłany: 26-11-2013, 19:57   

osmial pomyśl teraz ile zaoszczędzisz sobie a przede wszystkim innym trudu, jeśli po while(); dodasz jeszczelinijkę przerwy przed otwarciem bloku, żeby nikt nie miał wątpliwości jaka była twoja intencja.


Walczę jak lew, padam jak mucha

Micromouse Legend
ucgosu.pl - blog o programowaniu embedded i robotyce. Tematyka bardziej dla zaawansowanych.
Postaw piwo autorowi tego posta
 
 
osmial 



Posty: 15
Pomógł: 1 raz
Skąd: Piotrków Trybunalski
Programuję w:
c,asm
Wysłany: 26-11-2013, 20:22   

GAndaLF napisał/a:
osmial pomyśl teraz ile zaoszczędzisz sobie a przede wszystkim innym trudu, jeśli po while(); dodasz jeszczelinijkę przerwy przed otwarciem bloku, żeby nikt nie miał wątpliwości jaka była twoja intencja.


dzięki za radę, jest na prawdę przednia:) Teraz tylko wskaż mi miejsce gdzie napisałem, że taki kod jest czytelny. Widzę, że mylisz pojęcia, bo to co uważasz za pułapkę języka jest tak naprawdę złym (w sensie prowadzącym do nieczytelności) formatowaniem kodu.

Postaw piwo autorowi tego posta
 
 
Wyświetl posty z ostatnich:   
Odpowiedz do tematu
Nie możesz pisać nowych tematów
Nie możesz odpowiadać w tematach
Nie możesz zmieniać swoich postów
Nie możesz usuwać swoich postów
Nie możesz głosować w ankietach
Nie możesz załączać plików na tym forum
Możesz ściągać załączniki na tym forum
Wersja do druku

Skocz do:  

Nie rozwiązałeś swojego problemu? Zobacz podobne tematy: [Algorytmy] Sposoby ... [Mechanika] Jak wyko... [Inne] Obsługa kart ... [Mechanika] Jak prze...
lub przeszukaj forum po wybranych tagach: jezyka, pulapki


Powered by phpBB modified by Przemo © 2003 phpBB Group
Popularne kursy: Arduinopodstawy elektroniki