626

(644 odpowiedzi, napisanych Programowanie - 8 bit)

XXL - mam wątpliwości co do klasyfikacji na atariki. Dlaczego CIM są na czerwono? Przecież to są bardzo stabilne rozkazy. Za każdym razem działają tak samo - Czekają na przerwanie RESET. Powinno się wg mnie zmienić ich nazwę na WAR - WAit for Reset.

627

(4 odpowiedzi, napisanych Miejsca w sieci)

Facet odwalił kupę brudnej roboty. WUDSN wydaje się bardziej dopracowany, ale na tej bazie już relatywnie łatwo dałoby się zrobić sensowny support dla madsa i altirry.

628

(73 odpowiedzi, napisanych Fabryka - 8bit)

Ale czy to jeszcze Atari ? ;)

629

(21 odpowiedzi, napisanych Zloty)

Coś ten link nie rabotajet.

630

(19 odpowiedzi, napisanych Bałagan)

Przeczuwałem, że boost::format nie jest demonem prędkości, ale nigdy tego nie zbadałem, bo nie używałem go w miejscach krytycznych czasowo, a jest całkiem funkcjonalny. Fajnie, że są szybkie alternatywy, ale w moim przypadku w firmie staramy się nie zwiększać zależności od zewnętrznych biblioteki i rzadko wychodzimy poza boosta.
Eigen jest przykładem bardzo specjalistycznej biblioteki, w której bardzo dobrze znajdują zastosowanie dociążenia operatorów, bo właśnie do takich rzeczy zostały one pomyślane - do zastosowań, w których użycie operatora jest intuicyjne. Biblioteka byłaby mniej poręczna w użyciu, gdyby musiała działać na funkcjach (tak jak w javie) i dla takich rzeczy, dobrze, że dociążanie operatorów jest możliwe, nawet kosztem pewnych zawirowań, jak z operatorem &&.

631

(19 odpowiedzi, napisanych Bałagan)

Przespałem się z tym i wydaje mi się, że większość Twoich obiekcji wiąże się z kompatybilnością z C i to nie chodzi Ci o stopień kompatybilności, ale o sam jej fakt. Jeśli tak postawimy sprawę, to z tego co pamiętam sam Stroustrup nie ukrywa, że jest z tym bardzo dużo problemów i jak wykazałeś, nie trzeba ich długo szukać. Inaczej jednak być nie mogło i nie będzie. Pierwszym projektem Stroustrupa był „C with classes”, z którego ewoluował C++, więc ścisłe powiązanie z C jest faktem, a stopień kompatybilności nie jest przypadkowy – jest najlepszy jaki udało się osiągnąć na zasadach kompromisu. Z tego co widzę, to potrzebujesz po prostu języka D i wytykasz w C++ te fragmenty, w których przeziera w nim C, a które zostały zrealizowane inaczej w D, porzucając tę kompatybilność. Niestety pod tym względem nie wiele można podyskutować, bo C++ już taki jest, inny nie będzie, a dyskusja przerodziłaby się w debatę teologiczną :)
Nie za bardzo mogę jednak się zgodzić, że winę za to ponosi komitet standaryzacyjny. Zapewniam Cię, że do C++ nie dostaje się nic nieprzemyślanego. Czytając ich listę mailingową można się przekonać ile rozpatrują propozycji zmian w C++, jak długo szlifowane są obiecujące zmiany i ile z nich naprawdę przechodzi. Każda zmiana wiąże się z ryzykiem złamania istniejącego kodu i decyzje są podejmowane bardzo ostrożnie. A najwięcej problemów jest nie z tym, co zostało dodane do C++, a z tym co jest dziedziczone z C, więc teoria o braku porozumienia pomiędzy autorami ficzerów jest bardzo naciągana. Fory mieli ludzie od D, bo napisać język od nowa wzorując się na C++, C# itp. już jest łatwe ;)
W kwestii konkretów nie podoba Ci się formatowanie wyjścia. Mi też się nie podoba, ale trzeba pamiętać, że jest to niskopoziomowy i bardzo ogólny mechanizm strumieni, które można konfigurować na takie przetwarzanie elementów, jakie potrzebujemy. Strumień ze swej natury nie jest niestety poręczny w przypadku formatowania innego niż domyślne i najważniejszy problem jaki tu widzę, to że nie istnieją standardowe wrappery ułatwiające nietrywialne formatowanie. Nie wiem, czy to wina nieprzemyślenia architektury, ale najwidoczniej uznano, że bardziej wyuzdane formatery byłyby bardziej narażone na krytykę ze względu na mnogość preferencji użytkowników w tym temacie i zdecydowano się na standaryzowanie tylko najprostszego modelu, pozostawiając rozwój konkretnym użytkownikom wedle ich potrzeb. Ze swojej strony mogę polecić boost::format.
Z regułami dowiązywania rzeczywiście nie zrozumiałem pytania. To o co pytasz, to bardzo specjalistyczna działka i moje stanowisko jest takie, że dopóki nie jesteś twórcą biblioteki, to nie powinieneś się o to martwić. Reguły są ustalone tak, aby wszystko działało i nawet cieszę się, że nie muszę się o to martwić i poza brzegowymi przypadkami, w których na własne życzenie pakuję się w kłopoty, rzeczywiście się nie martwię. Cały temat jest zresztą jeszcze trudniejszy odkąd w C++11 są r-value referencje i jak ostatnio się tym zajmowałem, to musiałem przestać w obawie przed eksplozją głowy. Ciekawi mnie, czy w D te reguły są prostsze ;)
Co do postawionej tezy, to zgadzam się, że C++ cierpi na kompatybilność z C bardzo podobnie, jak MADS cierpi na kompatybilność z QA, ale wina leży tylko w pierwotnym założeniu kompatybilności, które w szerszej perspektywie zdaje się jednak mieć więcej korzyści niż wad – możliwe, że MADS nie stałby się de facto standardem, jeśli nie dałoby się skompilować w nim źródeł z x-asma a pośrednio i z QA. Podobnie, jakby C++ nie potrafił kompilować kodów w C, możliwe, że nie odniósłby takiego sukcesu. Względny sukces języka D (ale tylko względny, bo trudno uznać go jeszcze za język „produkcyjny”) opiera się na wcześniejszym sukcesie C++, C# i Javy.

632

(19 odpowiedzi, napisanych Bałagan)

Dziękuję za uznanie włożonego wysiłku, bo 1/3 dnia to pisałem. Polecam się też na przyszłość. Jakby kogoś paliły jakieś pytania, to chętnie odpowiem :)
Dla tych, co chcą posłuchać jaki fajny jest C++11 to polecam ten wykład autora. Stroustrup był nawet z nim kilka tygodni temu na Uniwerku Wrocławskim, ale niestety moją wersję "Języka C++" ukradli mi na studiach i nie dostałem autografu ;)

@wieczor: No to mnie przyszpiliłeś z tym małym atari. Nie mam teraz innego wyjścia, jak napisać na niego kompilator C++ ;)

633

(19 odpowiedzi, napisanych Bałagan)

@epi:
Kompatybilność z C jest oczywista – aby korzystać z bazy bibliotek napisanych w C, które kompilują się po kosmetycznych poprawkach / uściśleniach. Mógłbyś podać jednak kilka konkretów tych dziwactw? Nie twierdze, że C ich nie miał, ale np. nie rozumiem uwagi o powielaniu tekstu w nagłówkach? Chciałbyś żeby C++ porozumiewał się pomiędzy modułami jak C# - bez includów? To chyba inna para kaloszy nie możliwa do sensownego zaimplementowania.
Nie za bardzo czuję obiekcje to std::vector. Rozumiem, że boisz się pomieszania iteratorów, ale ja tu nie widzę żadnego problemu. Jak piszesz w C to też nie masz pewności, że dwa wskaźniki wskazują na tę samą tablicę, ale w przypadku vectora tak źle nie jest. Np. w microsoftowej implementacji STLa można włączyć feature „checked iterators”, dzięki któremu operacje na iteratorach dokonują dodatkowych sprawdzeń czy dotyczą tego samego kontenera itd. Dzięki niej spokojnie wykryjesz takie błędy, a najlepsze jest to, że to jest opcja, którą w każdej chwili możesz wyłączyć i cieszyć się pełną wydajnością równoważną operacjom na wskaźnikach bez żadnego ukrytego sprawdzania zakresów jak w C# czy w Javie
Uwagi do iostream niestety nie rozumiem. Wyjaśnij proszę.
Biblioteka C jest dla kompatybilności, jakbyś chciał skompilować kod w C. Nikt nie każe Ci jej używać, bo powszechnie wiadomo, że biblioteka C++ jest lepsza ;)
iostream i wyjątki: nie zgodzę się. Operacje na strumieniach są naturalnie narażone na niepowodzenia (użytkownik podał literkę, a chciałeś cyfre, plik się skończył itd.). Wyjątki w C++ są od sytuacji wyjątkowych, które chciałbyś obsługiwać w innym miejscu, bo nie chcesz dbać o nie w miejscu użycia. W przypadku strumieni ich użycie jest takie lokalne, że gdzie pisałbyś tę obsługę? Pewnie tuż pod użyciem. I czy to ma sens?  Lepiej sprawdzić status jeśli Cię to interesuje. Dodatkowo pachnie to już sterowaniem przez wyjątki. Zupełnie jak ten idiotyzm w .NET, w którym metoda int.Parse rzuca wyjątek jak się nie uda, i musieli ratować się dodając metodę TryParse.
Co do „deklaracji funkcji s2 zwracającej string” to masz rację. Jest to pewna niezręczność… chociaż przepraszam. To była niezręczność, gdyż C++11 do inicjalizacji wprowadził notację klamrową, a więc teraz piszemy string s1{"q"}  i string s2{}. A ten błąd jest i tak tylko powierzchowny, bo wychodzi przy pierwszej próbie kompilacji użycia s2.
a && b – winny. Nie możesz zdefiniować leniwego && dla swojego typu. Tu jest faktycznie pewne zamieszanie i trzeba uważać. Dociążania operatorów nie powinno uczyć studentów zbyt wcześnie, bo to jednak zaawansowany feature i raczej przeznaczony dla twórców bibliotek.
Czy przytoczę z pamięci reguły wiązania? Nie. Ale nawet programista C powinien wiedzieć, że tam gdzie ma wątpliwości, to czytelnik kodu też pewnie będzie je miał i trzeba dodać nawiasy. Czy to wada C++?
class czy typename? To jest wg ciebie jakiś palący problem? Ja w deklaracjach szablonów typowych raczej piszę typename, ale to jest sprawa indywidualna i też zależna od kontekstu, a nawet można potraktować to jako komentarz wyrażający intencje programisty.
using namespace? Tu też jest sprawa indywidualna, ale w moim środowisku using jest traktowane jak element złego stylu programowania. W każdym bądź ma swoich miłośników i jakieś tam zastosowania. Nie widzę w tym nic złego.
Zmienna In/out? Odpowiedziałem w pierwszym punkcie Foxowi.
Domyślnie oczywiście ++i, a i++ tylko tam, gdzie to potrzebne. A operator++(T&, int nieuzywany); to rzeczywiście hack :)

Ogólnie bardzo niezbornie wyraziłeś te swoje uwagi i średnio przekonująco (z wyjątkiem przypadkowej deklaracji funkcji czy prawie leniwych operatorów). Ogólnie nie widzę, dlaczego wg Ciebie powinno to dyskredytować w jakiś sposób C++.

634

(19 odpowiedzi, napisanych Bałagan)

@fox:

  1. Obie wersje kompilują się do tego samego, więc o żadnej optymalizacji nie może być mowy, ale ze względu na gwarancje języka mają odmienną semantykę, przez co są używane w innych sytuacjach. Granica jest subtelna i często płynna i niekiedy świadomie przekraczana, ale pozwala na wyrażenie intencji programisty.
    Wersji a używam w dwóch kontekstach:

    • gdy bar jest dużym obiektem ze sterty oraz gdy foo potrzebuje go użyć wołając metod nie-stałych (wybieram wersję void foo(Bar const* bar) gdy chcę ograniczyć wołalność do stałych metod). W grę wchodzi tylko wołanie metod (względnie dobieranie się do pól, jeśli to struktura). Niedopuszczalne jest nadpisanie ( *bar = bang ) oraz zapamiętanie wskaźnika na później, gdyż dostając goły wskaźnik nie mamy gwarancji jego żywotności – goły wskaźnik wpadający do funkcji każe domniemać, że to obiekt tymczasowy do natychmiastowego użytku. Nawiasem mówiąc goły wskaźnik nigdy nie powinien pojawić się poza argumentem funkcji, gdyż nie ma on semantyki własności (na co C++owcy są bardzo uczuleni), stąd przykazanie użyj – nie zapamiętuj. Jego użycie jest uzasadnione tylko byciem wspólnym mianownikiem dla standardowych wskaźników unique_ptr (o unikalnej właśności) oraz shared_ptr (o dzielonej właśności – jest to wskaźnik z licznikiem odwołań),

    • gdy bar ma służyć jako parametr opcjonalny i jego pustość niesie dodatkową informację, którą możemy wykorzystać przy projektowaniu algorytmu, a więc tak jak w C.

    Wybieram b, gdy intencją jest modyfikacja bar, który najczęściej jest obiektem automatycznym. W szczególności bar może być dużą strukturą, którą potrzebujemy wypełnić w funkcji foo. Skoro rolą foo jest wypełnienie bar, to nie ma ona sensownego zachowania, gdyby bar był pustym wskaźnikiem i tu przydaje się gwarancja istnienia bar.
    Nie wiem jak bardzo świadome było pytanie, ale tak samo jak void foo(Bar * bar) ma brata foo(Bar const* bar), to void foo(Bar & bar) ma o wiele popularniejszego brata void foo(Bar const& bar), który zabrania modyfikacji bar. Jest on używany w kontekstach korzystania z bar bez jego modyfikowania gdy operujemy na wartości. Jest to zatem klasyczne wykorzystanie referencji jako aliasa na wartość, co jest niezbędne przy dociążaniu operatorów. Celowo napisałem wartość, gdyż do takiego foo możemy podać literał, czy wyrażenie obliczające się do Bar, a więc niekoniecznie musi być to konkretna zmienna o istniejącym adresie, tak jak przy wskaźnikach. Stałych referencji używamy przy definiowaniu operatorów, konstruktorów kopiujących, klauzul łapania wyjątków itd.
    Nie mogę jeszcze nie wspomnieć o kuzynie: r-value referencji, przez co programista C++ widzi jeszcze wersję c:
    c. void foo(Bar && bar) { /* kod */ }
    Jest to bardzo silny mechanizm, gdyż ta funkcja dowiąże się tylko to wartości, która nie ma nazwy, a więc wartości tymczasowej, która zginie zaraz po zakończeniu działania funkcji foo, dzięki czemu możemy ukraść jej zasoby, bo i tak nikt tego nie zauważy. Na bazie r-value referencji budowane są w C++ konstruktory przenoszące, czyli takie, które tworzą nowy obiekt na bazie starego obiektu tego samego typu, który zaraz zostanie zniszczony – stąd możemy bezpiecznie ukraść mu pamięć, jeśli jest to np. jakiś kontener.
    Zagadnienie jak widać jest bardzo szerokie, ale wspomnę, że dzięki konstruktorom przenoszącym wcale nie jest głupia konstrukcja czwarta:
    d. void foo(Bar bar) { /* kod */ }
    Jest to wzorzec dla settera, czyli metody, która przejmuje bar na własność. foo mogło być wywołane z wartością tymczasową (więc bar „przeniósł” ją do siebie) lub z wartością nazwaną (wówczas wykonała się kopia). Ciało foo w takiej okoliczności powinno przenieść zawartość bar do pola klasy, której jest metodą. Dzięki temu mamy jedną metodę i żadnego kopiowania, jeśli nie jest ono konieczne.

  2. Należy odróżnić błędy od sytuacji wyjątkowych. Gdy parsuję tekst napisany przez użytkownika, błędy w takim tekście nie są niczym wyjątkowym, lecz czymś spodziewanym i aktywnie testowanym. Wyjątki są tu nie na miejscu. Gdy jednak zabraknie mi pamięci, albo nie znajdę karty graficznej, na której ma działać moja gra, to już jest sytuacja wyjątkowa, o którą nie powinienem się martwić w normalnym toku działania programu i tylko skrajni pesymiści przy każdej alokacji itd. sprawdzają czy się udała. C++ jest językiem dla optymistów, których interesuje pozytywna ścieżka wykonania programu (tzw. ścieżka sukcesu) i nieoczekiwane niepowodzenia traktują jako sytuacje wyjątkowe, dla których piszą obsługę w odpowiednich miejscach programu. Wyjątki są mechanizmem na tyle przenośnym na ile wspiera je kompilator i system operacyjny (a poza jakimiś dzikimi embedami są wpierane wszędzie) i powinny być używane wszędzie z wyjątkiem systemów czasu rzeczywistego, czy fragmentów wrażliwych na czas wykonania, gdyż nie istnieje deterministyczna metoda stwierdzenia maksymalnego czasu obsługi wyjątku. Gdy żaden wyjątek nie zostanie rzucony, we współczesnych implementacjach nie ma żadnego narzutu na czas wykonania programu. Dodatkowy czas obsługi możemy spokojnie zaniedbać, gdyż tyczy on się sytuacji… wyjątkowych. Gdy ktoś uważa inaczej, to znaczy że sytuacja, o której myśli, wcale nie jest wyjątkowa i powinien przeprojektować algorytm.
    W standardowym C++ nie można ignorować istnienia wyjątków, gdyż standardowy operator new rzuca wyjątek w przypadku braku pamięci, co jest kluczowe w implementacji standardowych kontenerów, które zakładają, że instrukcja zaraz po alokacji, ma zaalokowaną pamięć. Wzorem biblioteki standardowej zakładając, że wszystko się udaje, upraszczamy dramatycznie kod, gdyż nie trzeba sprawdzać, czy udało się to, czy udało się tamto… po prostu piszemy kod, tak jakby się udało, a sytuację, gdy się nie uda, obsługujemy jako sytuację wyjątkową.

  3. Do 90% operacji na łańcuchach znaków użyję std::string. Jest to klasa z semantyką własności względem pamięci zajmowanej przez napis i z podstawowymi operacjami edycyjnymi. Const char * to tylko wskaźnik, więc nie jest de facto łańcuchem znaków, a LPCTSTR ma różne znaczenie w zależności od unicode’owości (i nie jest to typ standardowy), więc trudno je porównywań. Frameworków nie używam, ale zdarza mi się użyć kilku narzędzi napisowych z boosta. Klasy string sam nie implementuję, bo już jest. Co najwyżej mogę zaimplementować coś, co bardziej nadaje się do konkretnego zastosowania i co załatwia kilka procent z pozostałych 10%, gdyż std::string nie jest 100% wpasowana w STL, gdyż nie jest klasycznym kontenerem danych. Jest napisem.

  4. Operatory logiczne i relacyjne zwracają wartość typu bool, a w praktyce wystarczy coś konwertowalnego do bool, gdyż operacjom selekcji wystarczy wyrażenie, które da się do boola skonwertować. Tak działa kompatybilność z C, że taki „if” nie bierze inta równego albo różnego od zera, tylko boola, a int potrafi się do niego skonwertować (oczywiście statycznie, w run time wszystko jest po staremu, C++ tylko lepiej dba o typy wyrażeń).

  5. Użyję C++. Nie znam architektury, którą warto się zainteresować, która nie wspierałaby C++.

  6. Prawda. Wszystkie kompilatory mają błędy. Sam kilka znalazłem i zgłosiłem Microsoftowi. Wskaż mi duży projekt w C, który nie obchodzi błędów kompilatora, szczególnie, że C jako język super przenośny powinien obsługiwać X platform i Y kompilatorów, z których każdy ma swoje kruczki. Prawdę mówiąc nawet zdarzają się błędy języka. Wystarczy zerknąć na issue list komitetu standaryzacyjnego.

  7. Ta składnia stanowi w C++ błąd. W C można było po cichu zrzutować void* na cokolwiek miało się tylko ochotę, dzięki czemu wskaźnik na cokolwiek zwracany przez malloc mógł być wprost zinterpretowany jako wskaźnik na to co chcemy. C++ na to nie pozwala, gdyż w C++ typ jest graczem pierwszoplanowym i bezpieczeństwo typów jest jego kluczową własnością. Dlaczego tak jest lepiej? W C mogłeś np. napisać int *i = malloc(1); co dla początkującego programisty, który nie czyta dokumentacji, wygląda całkiem sensownie, a niesie ze sobą brzemienne skutki. C++ zniechęca do takiej konstrukcji oferując natywny odpowiednik w postaci int * i = new int[1]. Nie jest to najszczęśliwszy zapis, ale jest to prosty odpowiednik, który dba o typ wyrażenia. Operator new jest karmiony typem jaki chcemy zaalokować oraz opcjonalnie liczbą elementów (a nie liczbą bajtów) i zwróci wskaźnik o typie int*, który z ochotą zostanie przypisany do zmiennej i. Nie potrzeba tu żadnego rzutowania, a mamy bezpieczeństwo typów. Dodatkowo new woła konstruktor tworzonego obiektu, co nam załatwia wstępną inicjalizacje pamięci, czego w C nie mieliśmy, a destruktor wołany po delete (bo nota bene zapomniałeś napisać w swoim przykładzie free i doznałeś wycieku ;p) woła destruktor, który sprząta po obiekcie (szczególnie takim nietrywialnym).
    A jak już jesteśmy przy alokacji zasobów, żaden (przyzwoity) programista C++ nie trzyma pamięci jako gołe wskaźniki, bo wie, że może zapomnieć o delete (albo nawet jak nie zapomni, to może mu w tym przeszkodzić wyjątek) i skrupulatnie dba o własność zasobu wg metodologii RAII i raczej napisałby std::unique_ptr<int> i( new int[1] ); przez co miałby pewność, że zasób zostanie automatycznie zwolniony (poprzez zawołanie destruktora obiektu std::unique_ptr<int>) w momencie zamknięcia bloku zawierającego i. Programiści C++ są leniwi i nie dbają o te wszystkie detale, z którymi walczą programiści w C. Oni zwalają je na kompilator.

  8. Oczywiście #include <iostream>. iostream nie jest nagłówkiem C, stąd brak rozszerzenia. W momencie, gdy zastanawiano się jakie rozszerzenie dać nagłówkom C++ (hxx? hpp?), ktoś wpadł na pomysł, że nie trzeba dawać żadnego :)

  9. Pytanie jest tendencyjne ;) Wszystkie tak zwane „nowoczesne języki programowania” mają dziedziczenie wielobazowe. Z tą różnica, że np. Java czy C# pozwala na dziedziczenie tylko interfejsów, co nazywa ich implementowaniem. W C++ interfejsy są pod postacią klas czysto wirtualnych, więc de facto można definiować sobie interfejsy i je implementować. C++ pozwala na więcej. Pozwala, aby klasy bazowe miały implementacje metod, a nawet miały pola. Dzięki czemu obiekt pochodny może posiadać wiele podobiektów bazowych. Można nawet zadeklarować niektóre z podobiektów jako wirtualne, przez co będą one występowały tylko raz. Jak nie czujesz się na siłach, aby korzystać z tych mechanizmów – nie rób tego i używaj tylko klas czysto wirtualnych (tzw. interfejsów), ale jeśli wiesz co robisz, to można za pomocą tego systemu zaimplementować wiele ciekawych funkcjonalności, które jednak mogą wykraczać poza „kurs podstawowy”. C++ daje narzędzia i od umiejętności programisty zależy jak ich użyje (łącznie ze zrobieniem sobie krzywdy).

  10. this jest wskaźnikiem i jest wskaźnikiem, bo tak. ;)

  11. Odpowiedź to d. Jest to program, w którym programista C dowodzi, że nie rozumie interakcji dziedziczenia z tablicami w stylu C i pokazuje, że C++ pozwala mu na zrobienie sobie krzywdy. Nieźle mnie to zaskoczyło, bo sam bym nie wpadł na to, żeby napisać coś takiego. Klasa A zawiera jedno pole int. Klasa B zawiera podobiekt A z jednym polem int, oraz pole char*. Deklarując tablicę obiektów typu B przydzielasz każdemu pamięci na dwa pola (int i char*). Tu popełniasz pierwszy błąd. Na razie niewielki. Deklarujesz tablicę jak w starym dobrym C. Drugi błąd (ten już brzemienny) wiąże się z potraktowaniem tablicy jako wskaźnika na (jeden!) obiekt pochodny, który bardzo ładnie i grzecznie potrafi zrzutować się na wskaźnik na (jeden!) obiekt bazowy. Takie rzutowanie jest fajne, bo obiekt pochodny potrafi wszystko to, co bazowy, a nawet więcej, więc możemy traktować jakby był obiektem bazowym. Ale problem jest taki, że przekazałeś ten wskaźnik do funkcji, która oczekuje tablicy (!) obiektów bazowych. Są to dwa różne obiekty, a oszukałeś system typów raz uważając to za wskaźnik, a raz za tablicę. Z pierwszym elementem idzie pięknie, bo ta operacja jest zdefiniowana, ale pakujesz się w problemy wykonując operacje na wskaźnikach do obiektu pochodnego myśląc, że to obiekt bazowy, dzięki czemu pudłujesz w drugi element. Nie jest to poprawny program w C++ i jego wynik jest niezdefiniowany (łącznie z możliwością wytworzenia czarnej dziury pochłaniającej wszechświat). Nadużyłeś dobroduszności C++ w sposób nie do wykrycia przez kompilator i zrobiłeś siebie krzywdę pokroju int * i = malloc( 5 ). Jak poprawnie robi się takie rzeczy? Otóż w C++ nie używamy gołych tablic C w ogólności, a szczególnie jeśli operujemy na obiektach, które nie są obiektami C (a więc obiektach z dziedziczeniem, Ty popełniłeś ten błąd). W C++ można w tym miejscy użyć statycznej tablicy std::array<B,3>, albo kontenera std::vector<B>. Obu obiektów nie da się zrzutować na wskaźnik i nie udałoby Ci się napisać takiego programu, który wygląda sensownie, a takim nie jest. Stroustrup też ma coś do powiedzenia na ten temat.

  12. /Wall w kompilatorze Microsoftu jest bardzo pedantyczne i często wyświetla uwagi, które nie raportują zagrożenia, ale mogą dać wskazówkę programiście o zachowaniu, którego mógł nie być świadom, stąd zaincludowanie iostream wygeneruje stado komunikatów w stylu, że w jakiejś strukturze na końcu dodano trzy bajty paddingu, albo kompilator zadecydował, że nie będzie inlinował jakiejś tam funkcji zadeklarowanej jako inline i tym podobne błahostki. Odpowiedź zatem to b, gdyż w iostream kompilator dodał kilka paddingów i odpuścił sobie kilku inline’owań. Dobrym poziomem warningów jest /W3, ale też nie jest idealnie, bo wśród ostrzeżeń czwartego poziomu jest kilka moim zdaniem przydatnych i te włączam sobie manualnie (wymuszając ich poziom na trzeci).

EDIT: w punkcie 3. 95% + 10% != 100%. Poprawiłem :)

635

(124 odpowiedzi, napisanych Fabryka - 8bit)

@epi: Proszę bardzo. Nie wiem jak MADS, ale C++ ma z poprzednikiem dokładnie tyle kompatybilności ile trzeba oraz nie zawiera on żadnych nie do końca przemyślanych ficzerów dodanych z powodu braku porozumienia wśród tych, którym na nich zależało, co z kolei implikuje, że nie istnieją żadne rzekome nieoczywiste szczególne przypadki na styku tychże nieistniejących ficzerów. Nie ma również żadnych śladów nieskoordynowanego rozwoju o czym łatwo się przekonać analizując tryb pracy komisji standaryzacyjnej, a mnogość stylów programowania jest pożądaną cechą i oczywistą konsekwencją wieloparadygmatowości języka.

To oczywiście subiektywna opinia i jeżeli jednak uważasz inaczej, to fajnie jakbyś podał jakieś przykłady, do których można byłoby się odnieść, ale to już chyba w jakimś innym wątku, bo głupio tu tak perfidnie offtopikować.

636

(124 odpowiedzi, napisanych Fabryka - 8bit)

Epi: grząski grunt. Nie boisz się utonięcia, jak ktoś spyta o konkrety?

jellonek: Nie wiem, więc pytam: czy ca65 jest rozumiany przez WUDSN i przez Altirrę? Bo jeśli nie, byłby to konkretny argument.

637

(124 odpowiedzi, napisanych Fabryka - 8bit)

Dziękuję :)
Nie byłoby tej dyskusji, gdyby asembler bardziej trzymał nas w ryzach (dla naszego własnego dobra). Np. standard języka C++ pozwala na maksymalnie dużo. Ale nie więcej.

638

(124 odpowiedzi, napisanych Fabryka - 8bit)

Błędy podczas programowania są nieuniknione i software używany przez programistów powinien jak najlepiej pomóc w ich wykrywaniu. Dokładnie dlatego powstał np. taki Clang uczulony na częste błędy i nawet potrafiący zaproponować poprawkę. Jeżeli asembler uważa, że nie ma nic złego w "inx $00" to dla mnie jest to błąd w asemblerze.
Dodatkowo: gdy czytam kod i widzę w nim coś dziwnego, to tracę zaufanie do programisty. Wspomniane "inx #0" bardzo wzmogłoby moją czujność, bo widząc coś takiego, nie wiem, czy programista nie potrafi programować i myśli, że istnieje rozkaz inx #, czy się pomylił i chodziło mu o coś innego, czy świadomie dodał komentarz w tylko jemu znanej notacji, co jest bardzo nieładne i sugeruje mi, że programista nie chce żeby ktokolwiek czytał ten kod. Tak czy inaczej wnioskuję, że z tym kodem jest coś nie tak.

639

(124 odpowiedzi, napisanych Fabryka - 8bit)

QA to natywny asembler, w którym ze względu na ograniczenia platformy pojawiły się pewne uproszczenia. Bardzo niejasne z gramatycznego punktu widzenia reguły co jest komentarzem, a co nie, nie wydają mi się powodem do chluby i przykładem do naśladowania. Ale to było na atari i można to zrozumieć. Problem widzę w tym, że nikt nie zdecydował się na zerwanie niechlubnej kompatybilności odpowiednio wcześnie, zanim nie upowszechniła się cross-developerka. A wystarczyłby przełącznik "QA-compatible". Możliwe, że całkiem sensownym rozwiązaniem mógłby być jakiś przełącznik powodujący błąd, jeśli komentarze nie zaczynają się od znaku początku komentarza (czyli po pla nie mogłoby znaleźć się nic poza oznaczonym komentarzem).

Fox napisał/a:
 ldx #29
 sta:rpl ^00,x-
 inx #0

Nie wiem czy chcę wiedzieć jaki jest cel takiego zabiegu (obfuscation?), ale widać perlowcy lubią takie potworki.

640

(124 odpowiedzi, napisanych Fabryka - 8bit)

Otóż to. I dlatego uważam, że te wszystkie sklejki to chory pomysł. Tak jakby nie dało się napisać normalnie jedno pod drugim. Gdyby przynajmniej to było zarezerwowane dla instrukcji mających ten sam argument, ale widzę, że można sklejać co popadnie.

TeBe: Nie dałoby się dodać przełącznika wyłączającego te xasmowe sklejko-rozszerzenia, dla kogoś, kto z nich nie korzysta i nie chce napotykać na takie problemy?

641

(29 odpowiedzi, napisanych Sprzęt - 8bit)

65816 jest chyba mocniejszy, ale poniekąd aspiruje do bycia 16-bitowcem (16 MB pamięci adresowej itd), a 6809 jest jednak bardziej 8-bitowy (ale trudno tu dyskutować, bo granica jest bardzo nieostra). Siła 6809 drzemie w jego funkcjonalności. Lista rozkazów jest nawet bardziej ortogonalna niż 6502, bo większość rozkazów ma bardzo rozwinięte "adresowanie rozszerzone", dzięki któremu można pisać kod w pełni relokowalny. Niestety płaci się za to większą (niekiedy monstrualnie) liczbą cykli.

642

(29 odpowiedzi, napisanych Sprzęt - 8bit)

Doczytałem, że facet rozdał już kilka prototypów. Wygląda na to, że niedługo trzeba będzie uaktualnić jakiś emulator ;)

643

(29 odpowiedzi, napisanych Sprzęt - 8bit)

A to dobre. Zastanawiałem się nad tym, czy ktoś coś takiego kiedyś zmajstruje i voilà - jest :)
Wg mnie 6809 to najmocniejszy ośmiobitowiec w historii. Trudno powiedzieć czy w wydajności, bo średnią liczbę cykli na rozkaz raczej ma większą niż 6502, ale rozkazy ma o wiele potężniejsze i w rezultacie możliwe, że te same zadanie można wykonać na nim w mniejszej liczbie rozkazów. Trzeba byłoby zaimplementować na nim jakiś nietrywialny algorytm i się przekonać. Teraz już jest do tego platforma.

644

(10,041 odpowiedzi, napisanych Bałagan)

@Simius
1) Wg mnie nie, ale wg atari classic to chyba tak, bo bardzo mnie zaatakował jak to zasugerowałem. Spytaj go o to proszę sam, bo na mnie potrafi tylko szczekać.
2) Nie wiem i nie mam zdania. Nie chcę tracić życia na dyskusje w tym temacie.
@atari classic
W sumie nie muszę już nic dodawać, bo jak dla mnie zdyskredytowałeś się już wystarczająco. Gratuluję tylko osiągnięcia poziomu ekspertyz pani Marty Kaczyńskiej (patrz lądowanie Boeinga, w końcu tam był beton i nawet ogień) i życzę miłego dalszego szczekania.
@jellonek
Teraz ;)
Chciałem tylko ustalić, czy uważa, że ekspertem od katastrof lotniczych jest tylko on, czy może wszyscy :)

645

(10,041 odpowiedzi, napisanych Bałagan)

Tak jak myślałem, kreujesz się na eksperta od wypadków lotniczych przytaczając przykład katastrofy o diametralnie innym charakterze oświecając nas swoją mądrością poprzez wyroki kiedy to niebezpieczeństwo wzrasta (no bo w końcu jesteś ekspertem). Zmniejszasz tym inherentny poziom niebezpieczeństwa katastrofy smoleńskiej (patrzcie, tam były płomienie, a wszyscy przeżyli, a tu byle brzózka, a same trupy). Skoro zatem w Smoleńsku mieliśmy do czynienia z byle chlapnięciem w błoto (versus "uderzenie w twarde podłoże"), a samolot rozpadł się "w drobny mak", mimo że taki sam samolot potrafi nawet wykosić "kilkaset drzew" bez szkody dla pasażerów, przyczyną musiało być coś innego. Coś co jest skrzętnie ukrywane przez "media reżimowe i rząd", które "łżą jak bure suki" aby tylko ukryć prawdę. SPISEK!
I nie wykręcaj się jak węgorz, bo tylko się ośmieszasz nadając pozory mądrości swoim moherowym wywodom. Osobiście cały ten wątek mam tam gdzie słońce nie dochodzi i nie śledzę go od pół roku, a zaglądam tu sporadycznie aby się pośmiać, ale spiskowej erystyki nie znoszę.

646

(10,041 odpowiedzi, napisanych Bałagan)

Pytałem pierwszy. Wskaż analogię (poza tym, że to ten sam typ samolotu i że zapalił się i wybuchł).

647

(10,041 odpowiedzi, napisanych Bałagan)

Rzeczywiście. Zapomniałem, że masz problemy ze śledzeniem wątków. Otóż chodzi mi tylko o ostatni filmik, przy którym w próbach dowodzenia teorii spiskowych posuwasz się daleko poza rubieże logiki porównując sytuację nieudanego lądowania ze startem w skrajnie różnych warunkach. Czego to niby miało dowodzić? Domniemam, że byłeś w wojsku i widziałeś samolot z bliska (a może go nawet dotykałeś?) lub przynajmniej znasz się na inżynierii materiałowej i jej zastosowaniu w lotnictwie, więc, proszę, oświeć nas jakie widzisz analogie w tym filmiku i jakież to wnioski można z nich wyciągnąć.

648

(10,041 odpowiedzi, napisanych Bałagan)

A więc jesteś specjalistą od katastrof lotniczych. Rozumiem, że konsultowałeś przy wszystkich wymienionych przypadkach i nie mają one przed tobą żadnych tajemnic.
Weź się człowieku ogarnij. Żal dupę ściska przy czytaniu takich ekspertyz, bo na mój chłopski rozum trzeba być niezłym beretem, żeby nie widzieć różnicy pomiędzy startowaniem (w którym samolot prawie osiągnął prędkość nośną), a sytuacją tuż przed lądowaniem (w której samolot teoretycznie powinien mieć jeszcze 100 metrów do ziemi i zaczyna wytracać prędkość, aby być w stanie wylądować). Ale ja tam się nie znam, jestem tylko wieśniakiem.

649

(644 odpowiedzi, napisanych Programowanie - 8 bit)

Całkiem przypadkiem trafiłem na coś takiego: 6502 Opcode 8B (XAA, ANE) explained.

650

(11 odpowiedzi, napisanych Bałagan)

Posieję trochę defetyzmu, ale największym wg mnie osiągnięciem tej gry będzie wyznaczenie ścieżki, którą nie należy podążać. Naprawdę wyobrażacie sobie pseudo-paintballowców biegających z telefonami jak ludziki na filmie promocyjnym?