PROE wykład 9 C++11, rzutowanie, optymalizacja. dr inż. Jacek Naruniec



Podobne dokumenty
PROE wykład 8 biblioteki programistyczne, optymalizacja, inne... dr inż. Jacek Naruniec

PROE wykład 2 operacje na wskaźnikach. dr inż. Jacek Naruniec

PROE wykład 3 klasa string, przeciążanie funkcji, operatory. dr inż. Jacek Naruniec

Techniki programowania INP001002Wl rok akademicki 2018/19 semestr letni. Wykład 3. Karol Tarnowski A-1 p.

Szablony klas, zastosowanie szablonów w programach

Języki i techniki programowania Ćwiczenia 2

Podstawy programowania. Wykład: 5. Instrukcje sterujące c.d. Stałe, Typy zmiennych c.d. dr Artur Bartoszewski -Podstawy programowania, sem 1 - WYKŁAD

C++ - przeciążanie operatorów. C++ - przeciążanie operatorów. C++ - przeciążanie operatorów. C++ - przeciążanie operatorów

IMIĘ i NAZWISKO: Pytania i (przykładowe) Odpowiedzi

METODY I JĘZYKI PROGRAMOWANIA PROGRAMOWANIE STRUKTURALNE. Wykład 02

1. Wartość, jaką odczytuje się z obszaru przydzielonego obiektowi to: a) I - wartość b) definicja obiektu c) typ oboektu d) p - wartość

Programowanie w języku C++ Grażyna Koba

PROE wykład 4 pozostałe operatory, forward declaration, dziedziczenie. dr inż. Jacek Naruniec

Programowanie w języku Python. Grażyna Koba

Lab 9 Podstawy Programowania

W dowolnym momencie można zmienić typ wskaźnika.

Jeśli chcesz łatwo i szybko opanować podstawy C++, sięgnij po tę książkę.

Obszar statyczny dane dostępne w dowolnym momencie podczas pracy programu (wprowadzone słowem kluczowym static),

Języki C i C++ Wykład: 2. Wstęp Instrukcje sterujące. dr Artur Bartoszewski - Języki C i C++, sem. 1I- WYKŁAD

Functionalization. Funkcje w C. Marcin Makowski. 30 listopada Zak lad Chemii Teoretycznej UJ

C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy WSKAŹNIKI KLASOWE

Podczas dziedziczenia obiekt klasy pochodnej może być wskazywany przez wskaźnik typu klasy bazowej.

PARADYGMATY PROGRAMOWANIA Wykład 4

public: // interfejs private: // implementacja // składowe klasy protected: // póki nie będziemy dziedziczyć, // to pole nas nie interesuje

Języki programowania C i C++ Wykład: Typy zmiennych c.d. Operatory Funkcje. dr Artur Bartoszewski - Języki C i C++, sem.

Podstawy programowania. Wykład Funkcje. Krzysztof Banaś Podstawy programowania 1

JĘZYKI PROGRAMOWANIA Z PROGRAMOWANIEM OBIEKTOWYM. Wykład 6

Klasa jest nowym typem danych zdefiniowanym przez użytkownika. Najprostsza klasa jest po prostu strukturą, np

Wskaźniki w C. Anna Gogolińska

Dziedziczenie jednobazowe, poliformizm

Wprowadzenie do programowania

Wykład 8: klasy cz. 4

Programowanie obiektowe w C++ Wykład 12

Strona główna. Strona tytułowa. Programowanie. Spis treści. Sobera Jolanta Strona 1 z 26. Powrót. Full Screen. Zamknij.

Programowanie współbieżne Wykład 8 Podstawy programowania obiektowego. Iwona Kochaoska

Programowanie obiektowe. Literatura: Autor: dr inŝ. Zofia Kruczkiewicz

Wykład 5: Klasy cz. 3

Jak napisać program obliczający pola powierzchni różnych figur płaskich?

znajdowały się różne instrukcje) to tak naprawdę definicja funkcji main.

Programowanie w C++ Wykład 2. Katarzyna Grzelak. 4 marca K.Grzelak (Wykład 1) Programowanie w C++ 1 / 44

Podstawy programowania. Wykład 6 Złożone typy danych: struktury, unie. Krzysztof Banaś Podstawy programowania 1

Funkcje. Spotkanie 5. Tworzenie i używanie funkcji. Przekazywanie argumentów do funkcji. Domyślne wartości argumentów

Wykład 9: Polimorfizm i klasy wirtualne

Wskaźniki i dynamiczna alokacja pamięci. Spotkanie 4. Wskaźniki. Dynamiczna alokacja pamięci. Przykłady

Programowanie w C++ Wykład 5. Katarzyna Grzelak. 16 kwietnia K.Grzelak (Wykład 1) Programowanie w C++ 1 / 27

C++ Przeładowanie operatorów i wzorce w klasach

Dr inż. Grażyna KRUPIŃSKA. D-10 pokój 227 WYKŁAD 7 WSTĘP DO INFORMATYKI

Programowanie w C++ Wykład 2. Katarzyna Grzelak. 5 marca K.Grzelak (Wykład 1) Programowanie w C++ 1 / 41

Uniwersytet Zielonogórski Instytut Sterowania i Systemów Informatycznych. Ćwiczenie 3 stos Laboratorium Metod i Języków Programowania

Programowanie i struktury danych. Wykład 4 Dr Piotr Cybula

Podstawy Programowania

1 Podstawy c++ w pigułce.

Programowanie procesorów graficznych GPGPU

PLAN WYNIKOWY PROGRAMOWANIE APLIKACJI INTERNETOWYCH. KL IV TI 6 godziny tygodniowo (6x15 tygodni =90 godzin ),

Zaawansowane programowanie w języku C++ Klasy w C++

Podstawy programowania skrót z wykładów:

Informatyka II. Laboratorium Aplikacja okienkowa

Rozdział 4 KLASY, OBIEKTY, METODY

Wykład 1: Wskaźniki i zmienne dynamiczne

Informatyka I. Klasy i obiekty. Podstawy programowania obiektowego. dr inż. Andrzej Czerepicki. Politechnika Warszawska Wydział Transportu 2018

Programowanie w C++ Wykład 13. Katarzyna Grzelak. 4 czerwca K.Grzelak (Wykład 13) Programowanie w C++ 1 / 26

Wykład VII. Programowanie. dr inż. Janusz Słupik. Gliwice, Wydział Matematyki Stosowanej Politechniki Śląskiej. c Copyright 2014 Janusz Słupik

Podstawy Programowania C++

Wykład 9: Metody wirtualne i polimorfizm

Podstawy programowania. Wykład 6 Wskaźniki. Krzysztof Banaś Podstawy programowania 1

7. Pętle for. Przykłady

Wskaźniki a tablice Wskaźniki i tablice są ze sobą w języku C++ ściśle związane. Aby się o tym przekonać wykonajmy cwiczenie.

- - Ocena wykonaniu zad3. Brak zad3

1 Wskaźniki i zmienne dynamiczne, instrukcja przed zajęciami

Programowanie współbieżne i rozproszone

Programowanie obiektowe Wykład 3. Dariusz Wardowski. dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/21

Nowoczesny C++ Rafał Wasilewski 1

Politechnika Poznańska Wydział Budowy Maszyn i Zarządzania

Zmienne, stałe i operatory

C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy INNE SPOSOBY INICJALIZACJI SKŁADOWYCH OBIEKTU

Struktury Danych i Złożoność Obliczeniowa

Czym jest stos i sterta?

Java: kilka brakujących szczegółów i uniwersalna nadklasa Object

Zaawansowane programowanie w C++ (PCP)

Programowanie I. O czym będziemy mówili. Plan wykładu nieco dokładniej. Plan wykładu z lotu ptaka. Podstawy programowania w językach. Uwaga!

Laboratorium nr 9. Temat: Wskaźniki, referencje, dynamiczny przydział pamięci, tablice dynamiczne. Zakres laboratorium:

I. WSTĘP. Przykład 1. Przykład 2. Programowanie czyli tworzenie programów komputerowych (aplikacji komputerowych)

JAVA W SUPER EXPRESOWEJ PIGUŁCE

Automatyczne tworzenie operatora = Integer2& operator=(const Integer& prawy) { zdefiniuje. Integer::operator=(ri);

Podstawy programowania. Wprowadzenie

Dariusz Brzeziński. Politechnika Poznańska, Instytut Informatyki

Podstawy informatyki. Informatyka stosowana - studia niestacjonarne. Grzegorz Smyk

2. Klasy cz. 2 - Konstruktor kopiujący. Pola tworzone statycznie i dynamicznie - Funkcje zaprzyjaźnione - Składowe statyczne

Podstawy programowania obiektowego

Informacje ogólne. Karol Trybulec p-programowanie.pl 1. 2 // cialo klasy. class osoba { string imie; string nazwisko; int wiek; int wzrost;

TEMAT : KLASY DZIEDZICZENIE

Programowanie w języku C++

Programowanie obiektowe

Programowanie dla początkujących w 24 godziny / Greg Perry, Dean Miller. Gliwice, cop Spis treści

Podstawy Programowania Obiektowego

Język C++ zajęcia nr 2

KARTA PRZEDMIOTU. 1. Informacje ogólne. 2. Ogólna charakterystyka przedmiotu. Programowanie I C6

Wstęp do programowania

Programowanie Komponentowe Zarządzanie obiektami: kontenery

Niezwykłe tablice Poznane typy danych pozwalają przechowywać pojedyncze liczby. Dzięki tablicom zgromadzimy wiele wartości w jednym miejscu.

Transkrypt:

PROE wykład 9 C++11, rzutowanie, optymalizacja dr inż. Jacek Naruniec

Rzutowanie Różne typy rzutowania są szczególnie istotne przy dziedziczeniu. Załóżmy sobie prostą hierarchię klas: A B C

Rzutowanie Najprostsze rzutowanie w kierunku klasy bazowej: W tym przypadku sprawa jest bardzo prosta.

Rzutowanie Co w przypadku rzutowania w drugą stronę? Możemy popełnić błąd, bo możemy nie wiedzieć jaką klasę pochodną reprezentuje dany wskaźnik: Kompilacja przebiegnie poprawnie, błędy wystąpią w momentach odwołania się do błędnie rzutowanego obiektu.

Rzutowanie Okazuje się, że rzutowania możemy dokonać na wiele sposobów, m.in.: static_cast standardowe rzutowanie kiedy wiemy dokładnie co robimy, np. w przypadku prostej konwersji typów, przechodzenie z klasy pochodnej do bazowej itp. dynamic_cast rzutowanie dynamiczne, sprawdzające poprawność rzutowania. Wykaże błąd (NULL) w przypadku błędu. reinterpret_cast głównie służy do zmiany wskaźników, w szczególności przy przekazywaniu argumentów. const_cast rzutowanie, m.in. zmiennych const na typy bez const.

Rzutowanie static_cast W drugim przypadku nie jest wskazane!

Rzutowanie dynamic_cast

Rzutowanie reinterpret_cast Tutaj interpretuje wskaźnik jako inta:

Assert Kontrola poprawności aplikacji. Wykonuje się jedynie w trybie Debug (czyli deweloperskim). Jeśli warunek w funkcji nie jest spełniony, to wyświetlana jest linijka w której wystąpił błąd. Jeśli warunek jest spełniony, to funkcja nie wykonuje żadnej akcji.

Assert W trybie release (z optymalizacją) funkcja assert jest ignorowana przez kompilator (niezależnie od spełnienia warunku, program wykonuje się dalej).

Typedef Często zdarza się, że programiści chcą, aby standardowe zmienne nazywały się według własnych potrzeb. Np. chcemy zamiast słowa float stosować słowo lrzeczywista a listasloniowa zamiast Lista<Slon>: Typedefy są bardzo często spotykane przy różnych bibliotekach programistycznych, m.in. w WinAPI.

C++11 (C++0x) Nowy standard języka C++ Wprowadzony w 2011 roku. Założenia (m.in.): Ma być zgodny z poprzednim standardem. Ma ułatwić programowanie i naukę programowania C++ (m.in. wprowadzenie wielu elementów istniejących w innych językach programowania) Ma preferować rozszerzenia nad zmianą bazy języka. W chwili obecnej obsługiwany przez znaczną większość kompilatorów.

Nowe typy danych long long, unsigned long long (64 bitowe). char16_t, char32_t 16 i 32 bitowe reprezentacje znaków (np. do przechowywania znaków w UTF16 i UTF32) surowy napis (bez interpretacji), po cudzysłowie muszą być nawiasy:

Tuple Zbiór zmiennych o określonej strukturze. Typ szablonowy, sami określamy typy parametrów. Referencję na konkretny element otrzymujemy poprzez funkcję get<indeks>(zmienna). Wymaga #include<tuple>.

Nowe metody inicjalizacji Obiekty inicjalizowane zwykle nie nawiasami () a {}. Inicjalizacja nie wymaga znaku =.

Nowe metody inicjalizacji Inicjalizacja obiektów (wywołanie konstruktora z parametrem):

Nowe metody inicjalizacji Wygodna inicjalizacja wartości domyślnych składowych klasy:

Nowe typy deklaracji auto automatyczny dobór typu zmiennej w zależności od inicjalizacji:

Nowe typy deklaracji decltype nadanie zmiennej typu odpowiadającego typowi podanej zmiennej

Nowe typy deklaracji Nowa składnia definiowania typu zwracanej zmiennej (trailing return) parametr zwracany definiowany jest na końcu funkcji: oznacza dokładnie to samo Niedopuszczalne! bo d nie jest jeszcze znane kompilatorowi Poprawne! d jest przed decltype

NULL nullptr stosowany zamiast NULL. Oznacza rzeczywiście wskaźnik nie wskazujący na żadne dane, a nie wartość (np. 0). Pomaga uniknąć niektórych błędnych zapisów. Nie zadziała, bo próbujemy przypisać wskaźnik do liczby Zadziała, bo próbujemy przypisać liczbę do liczby

NULL

Inteligentne wskaźniki (smart pointers) Wspomaga proces zarządzania pamięcią (tworzenia/usuwania zmiennych dynamicznych). Inteligentne wskaźniki zachowują się jak wskaźniki, ale posiadają kilka rozszerzeń. Jest kilka typów inteligentnych wskaźników, m.in. auto_ptr już przedawniony unique_ptr ulepszony auto_ptr shared_ptr wskaźnik z licznikiem wskaźników wskazujących na tę samą informację

Inteligentne wskaźniki Obiekty zaalokowane dynamicznie są automatycznie usuwane po usunięciu obiektu auto_ptr. auto_ptr jest klasą, która ma konstruktory, destruktor itp. Nie obsługuje tablic (delete, nie delete[]).

Inteligentne wskaźniki Przypisanie inteligentnego wskaźnika auto_ptr powoduje zmianę jego właściciela : Ten wskaźnik na nic nie wskazuje, bo został przejęty.

Inteligentne wskaźniki Unique_pointer Obsługuje tablice (delete[]). Błąd na etapie kompilacji a nie uruchomieniu. Może być przenoszony (o konstruktorach przenoszących na dalszych slajdach), czyli np. zwracany w miejscach, gdzie unique_ptr jest zmienną tymczasową. Nie może być zwyczajnie kopiowany.

Inteligentne wskaźniki shared_ptr zlicza liczbą elementów wskazujących na to samo miejsce. Obiekt usuwa się po wyzerowaniu licznika.

Enumerate zakresowy Zmienne wyliczeniowe mogą odnosić się do konkretnego zakresu:

Foreach Pętla, która dla każdego elementu pewnego kontenera wykonuje osobno określone zadanie. For each w tym wypadku kopiuje każdy element z wektora ceny i wpisuje go za każdym razem do zmiennej cena (pętla wykona tyle iteracji tyle razy ile mamy elementów w wektorze).

Foreach Można także pobierać nie kopie elementów, a referencje (wykorzystamy dla powtórzenia auto): W tym momencie operujemy bezpośrednio na elementach wektora, nie na kopiach. W tym momencie zmiana obiektu wewnątrz pętli oznacza zmianę w wektorze.

lvalues, rvalues Aby wprowadzić efektywną metodę przenoszenia elementów należy zapoznać się z dwiema rodzajami elementów lvalue i rvalue. Nieformalna definicja 1: lvalue to taki element, który może występować zarówno po lewej jak i po prawej stronie równania (a1=a2 i a2=a1 to znaczy, że a1 i a2 to lvalue) Rvalue to taki element, który może występować tylko po prawej stronie równania (a1=2 ale nie 2=a1)

lvalues, rvalues Nieformalna definicja 2: Z lvalue możemy pobrać adres (int a1; b = &a1, więc a1 jest lvalue) Z rvalue nie możemy pobrać adresu np. z a+b, bo jest to obiekt tymczasowy np. z liczby (nie może być a = &2)

lvalue, rvalue Do lvalue odnosi się taka referencja jaką znamy (&), natomiast do rvalue - &&: do 2 i do wyniku i+i nie pobierzemy adresu

Konstruktor przenoszący Po co nam l i rvalue? Przyjmijmy prosty obiekt: dynamicznie alokowana tablica znaków

Konstruktor przenoszący Dodajmy konstruktor kopiujący i wykorzystajmy klasę:

Konstruktor przenoszący Jak widać przy operatorze + następuje stworzenie obiektu tymczasowego a potem jego kopiowanie (i całej tablicy). A gdyby zamiast kopiowania całego obiektu skopiować jedynie zmienne niewskaźnikowe, natomiast wskaźniki jedynie przekazać nowemu obiektowi? Tymczasowy obiekt i tak się skasuje, wskaźnik mu już niepotrzebny Operator + zwraca obiekt typu rvalue, więc stwórzmy dla niego specjalny konstruktor kopiujący: 1. Skopiowanie wskaźnika na tablicę z obiektu tymczasowego do aktualnego. 2. Ustawienie wskaźnika obiektu tymczasowego na nullptr dzięki temu destruktor obiektu tymczasowego go nie skasuje!

Konstruktor przenoszący Efekt? Nie kopiujemy tablicy a jedynie wskaźniki na tablice! Daje to ogromny wzrost wydajności. Nowy obiekt kradnie tablicę. Poprzednio: rvalue Teraz:

std::move Funkcja move określa, że zmienna może zostać przeniesiona operatorem przenoszącym (która domyślnie byłaby zwyczajnie skopiowana) napis pozostał niezmieniony wskaźnik na ciąg został zmieniony, nie możemy już z niego korzystać

C++11 Inne istotne elementy standardu: Wątki (wreszcie!) Default (domyślne funkcje, konstruktory, funkcja = delete zakazanie używania metody (np. operatora przypisania) Delegaci wykonanie w konstruktorze treści innego konstruktora tak, aby nie powielać kodu Wyrażenia regularne, Inne

Optymalizacja kodu C++ Metoda optymalizacji zależy od jej celu. Zwykle jest to poprawa wydajności (szybkości) aplikacji zmniejszenie ilości zajmowanej pamięci poprawa przejrzystości, modułowości kodu Na wykładzie zajmiemy się poprawą wydajności aplikacji.

Tryby debug/release Pierwszy krok tryb debug służy jedynie procesom deweloperskim. Innymi słowy: Kod debug jest znacznie wolniejszy od release, Program stworzony w trybie debug w wielu przypadkach nie uruchomi się na innych komputerach (np. przy VS wymaga obecności bibliotek VS na uruchamianym komputerze)

Tryby debug/release W trybie release kod jest optymalizowany, co uniemożliwia w większości przypadków podglądanie zmiennych. Poszukiwanie błędów można sobie umożliwić poprzez komunikaty kontrolne albo wypisywanie informacji do pliku. Coś co uruchamia się poprawnie w debug nie musi uruchamiać się poprawnie w release (po zoptymalizowaniu mogą ujawnić się błędy implementacji). Ogólnie każdy program finalnie powinniśmy uruchamiać w trybie release.

Opcje preprocesora Często mamy możliwość wybrania odpowiednich opcji kompilacji w zależności od zapotrzebowania/sprzętu: preferencja małego lub szybkiego kodu, Wykorzystanie operacji wektorowych procesora (np. SSE), Optymalizacja pod względem funkcji inline Opcje te zwykle ustawiane są w opcjach projektu (W VS zakładki C++->Optimization i C++->Code generation)

Funkcje inline Ciało funkcji oznaczonych jako inline są przez kompilator wstawiane w miejsce wywołania. Kompilator nie musi respektować naszego życzenia Zwykle w procesie optymalizacji kompilator sam najlepiej określa które funkcje powinny być inline.

Podział zadań na wiele wątków We współczesnych komputerach mamy zwykle więcej niż jeden procesor. Możemy z nich korzystać wywołując kilka niezależnych programów: Procesor 1 Procesor 2 Procesor 3 Edytor Przeglądarka Film Procesor 4

Podział zadań na wiele wątków Jeśli na jednym procesorze wykonywanych jest więcej niż jeden program (proces), to wtedy system dysponuje po kawałku czasu procesora dla każdego programu. Możemy także wykonywać nasz jeden program na kilku procesorach Przykład - mamy aplikację wyszukującą w danym ciągu znaków określoną sekwencję (w praktyce miałoby to sens gdyby ciąg był bardzo długi): ABCDFADCACBCBABABCBDBACBABABAB Dzielimy tekst na 4 podzbiory i każemy każdemu procesorowi zająć się jednym fragmentem: ABCDFADCACBCBABABCBDBACBABABAB Procesor 1 Procesor 3 Procesor 2 Procesor 4

Podział zadań na wiele wątków Na koniec uwspólniamy wyniki wyszukiwania Teoretycznie przetwarzanie powinno być 4x szybsze (chociaż w praktyce wyjdzie mniej) Do tworzenia i zarządzania takimi osobnymi podprogramami (a dokładniej wątkami) są już w każdym środowisku gotowe narzędzia. Można także przeprowadzać obliczenia na całych klastrach komputerów. C++11 wprowadziło klasę thread do zarządzania wątkami. Można wykorzystać narzędzia działające z automatu (jak np. OpenMP)

Podział na wiele wątków wersja ekstremalna Wykorzystanie kart graficznych ostatnio bardzo popularny sposób zwiększenia wydajności, w szczególności w: Grach. Przetwarzaniu obrazu. Badaniach naukowych. Dlaczego jest to dobre? [źródło: NVIDIA CUDA C Programming Guide]

Podział na wiele wątków wersja ekstremalna Pytanie to dlaczego nie używamy tego do wszystkiego? [źródło: NVIDIA CUDA C Programming Guide]

Podział na wiele wątków wersja ekstremalna GPU (Graphical Processing Unit) jest zorientowane na dużą ilość przetwarzania przy minimalnej ilości operacji sekwencyjnych. Dostęp do pamięci musi odbywać się w sposób zorganizowany. [źródło: NVIDIA CUDA C Programming Guide]

Programowanie GPU Jest wiele technik pozwalających na programowanie GPU, np: shadery w potoku generowania obrazu, CUDA (Nvidia), OpenCl (teoretycznie ATI i Nvidia i dowolne inne urządzenia, Open Computing Language) C++ AMP Na chwilę obecną najpopularniejsza i najlepiej rozwinięta jest CUDA (Compute Unified Device Architecture)

Profiler Profilery są niesamowicie użyteczne przy wykrywaniu wąskich gardeł programów. Zwykle zatrzymują program co pewien okres czasu (np. co 50 mikrosekund) i sprawdzają w której funkcji aktualnie znajduje się program. Otrzymane wartości są sumowane. W Visual Studio wybieramy Analyze->Launch Performance Wizard (opcja dostępna w wybranych wersjach VS).

Profiler Ewidentnie widać, że wąskie gardło jest w destruktorze!

Profiler Klikamy dalej na funkcję zwrocwskaznikwezla:

Profiler Widać, że błędem jest przechodzenie od ostatniego węzła, bo wtedy wiele razy uruchamia się wspomniana funkcja! Zmieńmy nasz destruktor:

Profiler Program wykonał się 2x szybciej!

Profiler Pójdźmy dalej poprawmy push_back tak, aby nie trzeba było za każdym razem przechodzić przez wszystkie elementy. Jak? przecież można trzymać też wskaźnik na ostatni element! Nasza lista byłaby efektywna przy dodawaniu na początek listy.

Profiler Przyspieszyliśmy nasz program do niecałej 1.5 sekundy, tj. ok. 5 razy! Można dalej? To już zależy od tego czego potrzebujemy modułowość/prostota/szybkość.

Inne metody optymalizacji Przy obliczeniach/algorytmach itp. pierwszą rzeczą zawsze jest poszukiwanie zysku szybkości w samym algorytmie. Czy wszystkie kroki trzeba wykonywać? Czy można gdzieś oszczędzić? Czy można przeorganizować kod aby był efektywniejszy? Można próbować pisania kodu asemblerowego zwykle kończy się tym, że kompilator potrafi zrobić to lepiej od nas. Kompilator nie będzie myślał za nas zoptymalizuje tylko kod który mu dostarczyliśmy.

Ankiety! studia.elka.pw.edu.pl