[#1] Który C?
Zacząłem uczyć się pisać w C na Amigę. Na razie używam Vbcc i Cubic IDE. Chciałem zapytać, którego kompilatora używać: vbcc czy gcc? Nie przewiduję pisania i kompilacji na pc. Mam pistorma więc szybkość procesora i ilość pamięci nie stanowią ograniczenia.
Głównie chodzi mi o to, żeby skupić się na programowaniu a nie walce z kompilatorem.
[#2] Re: Który C?

@mareq, post #1

Gcc. Vbcc jest w mojej opinii ciekawostką przyrodniczą - wystarczy spojrzeć na częstość aktualizacji i datę ostatniej tejże. Lata temu miałem z nim problem, że produkował zepsuty kod. A gcc 2.95, mimo że stare, to stabilne.

Zerknij może na gcc pack od Krashana.
1
[#3] Re: Który C?

@teh_KaiN, post #2

Rozszerzę nieco temat. Jak mają się one do SAS C lub innych C na Amigę? Znam tylko SAS C. Wiem, że to zabytek, ale wg mnie działający. I nie wiem na ile warto i czy w ogóle warto przesiąść się na coś innego.






Ostatnia aktualizacja: 18.02.2026 18:30:49 przez prz
[#4] Re: Który C?

@prz, post #3

To zależy od kilku czynników.

- GCC jest bardziej nowoczesny, ma lepsze algorytmy optymalizacji.

- Natomiast SAS/C, czy DICE to pełne IDE do pracy w języku C na Amidze.

Do tego łatwiej można linkować biblioteki linkowalne, czy wstawki asemblerowe w standardowym formacie Motoroli z oddzielnych plików.

Programiści Commodore pisali w SAS/C, pewnie też system w tym był kompilowany. Teraz też osoby związane z OS 3 wspierają SAS/C.

- VBCC z kolei ma mnóstwo targetów oraz binarki dla różnych systemów.
[#5] Re: Który C?

@mareq, post #1

Jeżeli chodzi o GCC 2.95.3 (o ile wiem ostatnia wersja działająca natywnie na Amidze) kontra VBCC, to moim zdaniem, popartym znajomością asemblera i disasemblacją skompilowanych programów, GCC generuje lepszy kod. Za to VBCC jest szybszy i ma nieco mniejsze wymagania pamięciowe. Ale to na PiStormie nie będzie miało żadnego znaczenia.

Za to z GCC masz otwartą drogę do zapoznania się z C++. Używam i jestem zadowolony. Jeżeli chcesz wygodnie zainstalować cały zestaw, zapraszam po GCC Pack.

Alternatywnie możesz rozważyć kompilator SAS/C, ale nie wiadomo skąd go oficjalnie wziąć i jego status prawny nie jest dla mnie jasny.
1
[#6] Re: Który C?

@Krashan, post #5

Ja bym dodał do dyskusji jeszcze pytanie, co chcesz pisać? Pod system czy nie?
... i czy chcesz używać assemblera inline czy nie. Jeśli np dema i gierki niesystemowe to jak dla mnie w VBCC łatwiej jest robić assemblerowe wstawki. Obu używałem tylko do cross-kompilacji ale w GCC użycie assemblera to była jakaś kosmiczna składnia.
[#7] Re: Który C?

@c64portal, post #6

Nie wiem w sumie jak się robi wstawki asmowe w VBCC. W GCC masz dwa rozwiązania.

Pierwsze to oddzielny plik z kodem w asmie skompilowany np. VASM-em i zlinkowany. Takie rozwiązanie zastosowałem np. w QoaPlay. Dekoder ramki QOA jest napisany w asmie i wywołany jako funkcja z kodu w C++.

Drugie to wstawianie wyrażeń asemblerowych wprost w kod. Kosmiczna składnia? Trochę tak, ale za to daje kosmiczne możliwości. We wstawce asemblerowej masz dostęp do zmiennych C, dzięki czemu np. kompilator sam może sobie dobrać rejestry albo tryby adresowania. Dość dobrze się poruszam w tej kosmicznej składni, więc mogę pomóc. Ta metoda jest najlepsza do wstawek krótkich (kilka czy kilkanaście instrukcji), obchodzących ograniczenia kompilatora albo języka. Zastosowałem ją między innymi w grze Untangle, żeby wyjaśnić GCC, że do pomnożenia dwóch liczb 16-bitowych wystarczy mu jedna instrukcja (plik "main.h", funkcja np. mul16()). Reguły języka normalnie powodują rozszerzenie tych liczb do 32 bitów, a potem kompilator stwierdza, że takiego mnożenia 68000 nie umie (ma je dopiero 68020) i usiłuje użyć funkcji bibliotecznej.

Ostatnia aktualizacja: 18.02.2026 21:46:58 przez Krashan
2
[#8] Re: Który C?

@c64portal, post #6

Generalnie chcę się skupić na pisaniu czysto pod system i raczej na programach użytkowych. Chcę jak najlepiej poznać sprzęt i system. Asembler na razie mnie nie interesuje.
1
[#9] Re: Który C?

@Krashan, post #7

Pierwsze to oddzielny plik z kodem w asmie skompilowany np. VASM-em i zlinkowany.

O, to ciekawe. Nie wiedziałem że można załączać kod z VASMa. Próbowałem za pomocą PhxAss ale nie działało.

Z tego by wynikało, że możemy do kodu GCC załączać kod asemblera w standardowym formacie.

GCC używa bowiem własnego, minimalistycznego formatu.

@Mareq

Akurat sam kompilator nie ma aż tak zasadniczego znaczenia. Ważny jest obsługiwany standard języka C oraz - według mnie - równiez obsługa standardów Amigi.

GCC gwarantuje w zasadzie najnowsze standardy.

Dopiero finalną postać kodu programu poddajemy optymalizacjom.

Zatem na początek zabawy/pracy z językiem C polecam dowolny kompilator. Ja zaczynałem od DICE i jest on dosć łatwy w obsłudze i instalacji.

SAS/C faktycznie nie jest dostępny oficjalnie, ale można pobrać oryginalne archiwum.
[#10] Re: Który C?

@Hexmage960, post #9

GCC używa bowiem własnego, minimalistycznego formatu.
Ale Vasm obsługuje ten format, wystarczy mu podać opcję -Faout.
GCC gwarantuje w zasadzie najnowsze standardy.
GCC 2.95.3 (a o takim mówimy, jeżeli chcemy kompilować na Amidze) raczej nie gwarantuje najnowszych standardów... Zwłaszcza jeżeli chodzi o C++.
1
[#11] Re: Który C?

@Krashan, post #5

Status prawny na 40 letnim sofcie/kompie ? No bez jaj

Ostatnia aktualizacja: 19.02.2026 08:40:46 przez dynx
1
[#12] Re: Który C?

@Hexmage960, post #9

O, to ciekawe. Nie wiedziałem że można załączać kod z VASMa.

Fajnie jest to pokazane w pakiecie GCC i pluginie do VSCode zrobionym przez Bartmana/Abyss, no ale to jest do cross compilacji. Ale działa fajnie i szybko można zacząć działać. tyle że tam jest też dużo nowszy GCC niż 2.95.

@Krashan
co do "kosmiczności" to miałem na myśli coś takiego np.:

void c2p_init (int chunkyx, int chunkyy, int scroffsy, int bplsize ){
	
	register volatile const void* _d0 ASM("d0") = chunkyx;
	register volatile const void* _d1 ASM("d1") = chunkyy;
	register volatile const void* _d3 ASM("d3") = scroffsy;
	register volatile const void* _d5 ASM("d5") = bplsize;

	__asm volatile (
		"movem.l %%d0-%%d7/%%a2-%%a6,-(%%sp)\n"

		"move.w #0,%%d2\n"
		"jsr c2p1x1_8_c5_040_init\n"
		
		"movem.l (%%sp)+,%%d0-%%d7/%%a2-%%a6"
	: "+rf"(_d0), "+rf"(_d1), "+rf"(_d3), "+rf"(_d5)
	:
	: "cc", "memory"
	);

}

Jest to fragment z jakichś moich kodów jak jeszcze chciałem pisać prosty engine pod GCCem
Zwłaszcza to mnie osłabiało:
: "+rf"(_d0), "+rf"(_d1), "+rf"(_d3), "+rf"(_d5)
;)
nie wiem do teraz co to znaczy... ale działało

przesiadłem się na vasm bo dodawanie procedur w asm jakoś prościej było mi zrozumieć. Ale pewnie zgodzimy się że to akurat kwestia gustu.
Co do całego wątku to miałbym taką (ostatnią) może radę.
Najlepiej po prostu zacząć coś robić, po jakimś czasie sam dojdziesz do tego, którym kompilator jest lepszy. Zakładam, że na początek to nie będą jakieś wielkie projekty programistyczne więc jest czas popełnianie błędów ale i na naukę.
[#13] Re: Który C?

@mareq, post #1

Według mnie, jeśli zaczynasz przygodę z C to nie ma na początkowym etapie znaczenia. Wcześniej czy później i tak będziesz musiał "trochę powalczyć" z kompilatorem. To narzędzia i trzeba nauczyć się je obsługiwać. W vbcc jest wsparcie dla c99 i jeśli już z automatu piszesz konstrukcje typu for (int i = 0, ... to potem ciężko się przestawić. W póżniejszym etapie warto przestawić myślenie z jednego pliku na wiele plików + nauka pisania makefile. W każdym razie nie będziesz się nudził. Wytrwałości.
1
[#14] Re: Który C?

@asman, post #13

Wcześniej trochę w C pisałem na mikrokontrolery. Na razie mam zabawę w przegryzienie się przez budowę i działanie systemu. W zakresie samego GUI bardzo mi pomaga Rebuild. Nie wiem na ile dobry kod on generuje w sensie poprawności ale jest dla mnie czytelny i działa w praktyce.
Odmiany C to na razie dla mnie czarna magia a C uczyłem się z książki do ANSI C. Jak się ma 50 lat na karku to nauka już tak łatwo nie przychodzi. szeroki uśmiech
[#15] Re: Który C?

@dynx, post #11

Może i bez jaj, ale po co mi to, skoro mam legalny, bardzo dobry kompilator? Prowadzenie działalności gospodarczej uczy ostrożności.
4
[#16] Re: Który C?

@Krashan, post #15

Dokładnie. Jak byłem mały to piractwo było normą. Teraz staram się być maksymalnie legalny. Jeśli ta mała społeczność amigowa ma funkcjonować to warto płacić są soft. Jeśli programowanie mnie wciągnie a nie okaże się miesięcznym zrywem to kupie sobie Cubic IDE, bo bardzo mi się podoba a to tylko chyba 20 euro. Z komercyjnych kompilatorów to znalazłem, że Storm C można też normalnie kupić.
1
[#17] Re: Który C?

@c64portal, post #12

miałem na myśli coś takiego
Osoba, która to napisała, nie do końca ogarniała o co chodzi i wyszedł mały potworek. Który zapewne działa, ale jest niepotrzebnie skomplikowany. Cała ta funkcja robi za interfejs między C/C++ a procedurą c2p1x1_8_c5_040_init, która jest zapewne napisana w asemblerze. Cztery argumenty tej procedury powinny się znaleźć w rejestrach d0, d1, d3 i d5, przy czym kod błędnie sugeruje, że na powrocie z funkcji te rejestry zawierają wartości, które mogą być później użyte. Co nie jest prawdą, bo funkcja nie zwraca żadnego wyniku.

Ogólny schemat wyrażenia extended asm jest taki:
__asm volatile ("<kod>" : <wyjścia> : <wejścia> : <modyfikowane_rzeczy>);

Sekcja wejść opisuje jak wartości wskazanych zmiennych C są umieszczane w kodzie asemblerowym, sekcja wyjść opisuje przenoszenie wartości z kodu asemblerowego do zmiennych C. Sekcja modyfikowanych obiektów wskazuje na niezachowane w kodzie rejestry procesora, rejestr znaczników ("cc") i pamięć ("memory").

Warto zauważyć, że tutaj autor zmienne w gruncie rzeczy wejściowe, umieścił w sekcji wyjść, dodatkowo za pomocą znaczka + oznaczając, że są również wejściami. To ma zerowy sens. Te argumenty powinny być w sekcji wejść, a sekcja wyjść powinna być pusta. Literki w "+rf" oznaczają dopuszczalne tryby adresowania. "r" to dla M68k dowolny rejestr danych lub adresowy. "f" to rejestr danych koprocesora, co znów jest mocno bez sensu, skoro i tak już wepchaliśmy te dane do konkretnych rejestrów.

Ja bym to napisał tak:
void c2p_init (int chunkyx, int chunkyy, int scroffsy, int bplsize )
{
  register int _d0 __asm("d0") = chunkyx;
  register int _d1 __asm("d1") = chunkyy;
  register int _d3 __asm("d3") = scroffsy;
  register int _d5 __asm("d5") = bplsize;

  __asm volatile (
    "movem.l d0-d7/a2-a6,-(sp)\n"
    "move.w #0,d2\n"
    "jsr c2p1x1_8_c5_040_init\n"
    "movem.l (sp)+,d0-d7/a2-a6"
  : 
  : "d"(_d0), "d"(_d1), "d"(_d3), "d"(_d5)
  : "cc", "memory"
  );
}

Usunąłem zmianę typu na "volatile const void*" (???), która służyła wyłącznie generowaniu ostrzeżeń kompilatora. Cztery argumenty są wejściami, znajdującymi się w rejestrach danych. Tutaj akurat jest to nieistotne, bo my de facto nie posługujemy się tymi argumentami w kodzie asemblerowym, więc kompilator tu nie wybiera trybu adresowania.

Przy standardowych opcjach kompilatora otrzymamy taki kod:
00000db4 <c2p_init(int, int, int, int)>:
 db4:   2f05           	move.l  d5,-(sp)
 db6:   2f03           	move.l  d3,-(sp)
 db8:   202f 000c      	move.l  12(sp),d0
 dbc:   222f 0010      	move.l  16(sp),d1
 dc0:   262f 0014      	move.l  20(sp),d3
 dc4:   2a2f 0018      	move.l  24(sp),d5
 dc8:   48e7 ff3e      	movem.l d0-d7/a2-a6,-(sp)
 dcc:   343c 0000      	move.w  #0,d2
 dd0:   4eb9 0000 0000 	jsr     c2p1x1_8_c5_040_init
 dd6:   4cdf 7cff      	movem.l (sp)+,d0-d7/a2-a6
 dda:   261f           	move.l  (sp)+,d3
 ddc:   2a1f           	move.l  (sp)+,d5
 dde:   4e75           	rts

Argumenty są tutaj przekazywane przez stos. Kompilator przytomnie zauważył, że użyte d3 i d5 należy przechować na stosie, potem zdjął argumenty, poumieszczał w rejestrach i zrobił to, co w asmie napisaliśmy. Dla porównania pokażę kod po użyciu opcji -mregparm która "zachęca" kompilator do przekazywania argumentów w rejestrach.
00000c50 <c2p_init(int, int, int, int)>:
 c50:    2f05            move.l  d5,-(sp)
 c52:    2f03            move.l  d3,-(sp)
 c54:    2608            move.l  a0,d3
 c56:    2a09            move.l  a1,d5
 c58:    48e7 ff3e       movem.l d0-d7/a2-a6,-(sp)
 c5c:    343c 0000       move.w  #0,d2
 c60:    4eb9 0000 0000  jsr     c2p1x1_8_c5_040_init
 c66:    4cdf 7cff       movem.l (sp)+,d0-d7/a2-a6
 c6a:    261f            move.l  (sp)+,d3
 c6c:    2a1f            move.l  (sp)+,d5
 c6e:    4e75            rts

Dwa odczyty z pamięci wypadły nam w ogóle (bo argumenty od razu były w d0 i d1), a dwa zmieniły się w przesunięcia z rejestru do rejestru. Polecam opcję -mregparm, kod jest jednocześnie i krótszy i szybszy.

Aha i jeszcze jedno. Zauważmy, że w gruncie rzeczy d3 i d5 są przechowane na stosie dwa razy, zupełnie niepotrzebnie. Zamiast ręcznie wpisywać w asma MOVEM.L, możnaby było dodać wszystkie rejestry z MOVEM.L do listy modyfikowanych rzeczy. Wtedy kompilator sam by to MOVEM.L ogarnął i d3/d5 byłyby zrzucane na stos tylko raz. Dodatkowo pominąłby zbędne przechowanie na stosie d0/d1/a0/a1, bo one z założenia mogą być modyfikowane bez przechowania (takie jest ABI AmigaOS).

Ostatnia aktualizacja: 19.02.2026 18:25:46 przez Krashan
1
[#18] Re: Który C?

@mareq, post #16

Jeśli ta mała społeczność amigowa ma funkcjonować to warto płacić są soft.
Tu na korzyść dynxa przemawia to, że SAS/C nie możesz już od dawna kupić od producenta, od czasu jak wyprzedał wszystkie fizyczne kopie. W tej sytuacji producent mógłby umożliwić zakup wersji elektronicznej (np. pobranie obrazów dyskietek) z zastrzeżeniem, że produkt nie ma już wsparcia technicznego, czy nawet zezwolić na bezpłatną legalną dystrybucję, ale tego nie zrobił.

Aktualnie jedyna możliwa droga nabycia SAS/C "full legal" to odkupić od kogoś oryginalne nośniki. Których cena może być zawyżona ze względu na "kolekcjonerskość", w dodatku mogą być niesprawne...
[#19] Re: Który C?

@Krashan, post #17

@Krashan
Dzięki za obszerne opisanie, ale.
Nie zrozum mnie źle, ale ja to wszystko wiem bo to ja w końcu napisałem ;) bazując na jakichś przykładach i po kilku dniach analizowania...
Chodziło mi tylko, że to właśnie jest niepotrzebnie tak skomplikowane zwłaszcza ta jedna linijka którą wyróżniłem.
Wiem, be nawet czytałem w dokumentacji gcc co to wszystko oznacza (te +/i literki ;) ), ba nawet to zrozumiałem, ale 6 miesięcy po tym fakcie teraz już nie pamiętam o co chodziło. A to powinno być tak że zerknę na kod i rozumiem co oznacza taki zapis. w VBCC + VASM jest pod tym względem dużo czytelniej.
Ale jeszcze raz nie mam zamiaru "Cię punktować" i jeszcze raz dzięki za obszerny opis. przyda się mi kiedyś a i innym pewnie też.
1
[#20] Re: Który C?

@c64portal, post #19

To co ja robię w przypadku wstawek asemblerowych to oddzielny plik z kodem asemblera i symbolami widocznymi z poziomu C i na odwrót.

Przykładowo jeżeli mam instrukcję, która zdecydowanie lepiej jest implementowana w asemblerze, to piszę funkcję w asemblerze w oddzielnym pliku.

_swap:
    swap d0
    rts

Jeżeli mam wymóg pobierania argumentów ze stosu, to też czynię:

_swap:
    move.l 4(a7),d0
    swap   d0
    rts

Następnie piszę prototyp funkcji w języku C:

unsigned long swap( unsigned long );

Jeśli interesuje mnie portowalność, implementuję tę funkcję również w C.

Co do kodu in-line, to ciekawie ma to rozwiązany język Amiga E.

Ale to, że w GCC jest taka możliwość, to duży plus tego kompilatora.

@Krashan

GCC 2.95.3 (a o takim mówimy, jeżeli chcemy kompilować na Amidze) raczej nie gwarantuje najnowszych standardów... Zwłaszcza jeżeli chodzi o C++.

Oczywiście chodziło mi o standardy takie jak C99. Nie chodziło o C++11 czy tego typu innowacje.

GCC 2.95.3 jest po prostu najbardziej na czasie.

Ja przyznam, że używam SAS/C pobrany z sieci, który w jakiś sposób znalazłem. Wspieram Amigowych autorów i namawiam każdego, by kupował oryginalne oprogramowanie.

Nabyłem np. MaxonC++, który ma zalety i wady.

Z darmowych to DICE, który został upubliczniony wraz z kodem źródłowym.

@Mareq
Odmiany C to na razie dla mnie czarna magia a C uczyłem się z książki do ANSI C. Jak się ma 50 lat na karku to nauka już tak łatwo nie przychodzi. szeroki uśmiech

Ja również uczyłem się z tej książki. Akurat 40+ lat to nie problem by się uczyć. Ja pod koniec zeszłego roku obroniłem pracę magisterską.

Uczyłem się m.in. o kompilatorach. Wreszcie udało mi się poznać to od środka, o czym zawsze marzyłem, nawet za młodu.

Gold ED i Cubic IDE to bardzo dobre pakiety (używałem pierwszego, ale drugi to rozszerzenie tego pierwszego). Można je skonfigurować w taki sposób, by łatwo kompilowały projekt.

W sumie Storm C 3 też posiadam, na płycie Amiga Developer CD v2.1. Kiedyś stosowałem.

Natomiast dziś - do edycji kodu - wolę Cygnus ED na Amidze (również mam oryginał) - to bardzo popularny edytor tekstu. Czasami piszę kod na PC i transferuję pliki.
[#21] Re: Który C?

@Hexmage960, post #20

Przykładowo jeżeli mam instrukcję, która zdecydowanie lepiej jest implementowana w asemblerze, to piszę funkcję w asemblerze w oddzielnym pliku.
Ja tam wolę mieć dobry kompilator. Popatrz:
static inline ULONG swap(ULONG x)
{
    return (x << 16) | (x >> 16);
}

ULONG swaptest(ULONG y)
{
    return swap(y) + 3;
}

00000dc4 <swaptest(unsigned long)>:
     dc4:	4840           	swap d0
     dc6:	5680           	addq.l #3,d0
     dc8:	4e75           	rts

Ty będziesz miał dodatkową parę JSR/RTS i - jeżeli kompilator przekazuje argumenty przez stos - odłożenie na stosie i zdjęcie ze stosu...
2
[#22] Re: Który C?

@Krashan, post #21

Słusznie, jeżeli kompilator dobrze to skompiluje, znajdzie odpowiednie instrukcje, to możemy to zastosować, szczególnie też że mamy portowalność kodu.

W pewnych sytuacjach, warto podać mu te instrukcje explicite, np. jeżeli nie jesteśmy pewni jak to skompiluje, bądź wiemy jak zoptymalizować ręcznie. Mogą to być rzadkie lub częstsze sytuacje.

Dla przykładu przy konwersji pomiędzy Big Endian a Little Endian, możemy to zapisać tak:

Konwersja słowa:

#define EndianWord(x) ((x) << 8) | ((x) >> 8)

Konwersja długiego słowa:

#define EndianLong(x) ((EndianWord((UWORD)x)) << 16) | (EndianWord(x >> 16))

I będzie bardzo zgrabnie.

Co więcej, zapewne w GCC, czy SAS/C możemy te makra zastąpić funkcjami in-line, jak w Twoim przykładzie i będzie to bardzo dobrze kompilowane.

Można też pomóc kompilatorowi, implementując ręcznie:

EndianLong:
    ror.w #8,d0
    swap  d0
    ror.w #8,d0
    rts

Bo to są akurat dość rzadko stosowane w C instrukcje. SAS/C ma specjalne makra, które są zamieniane na rotację bitową i swap.

Moim zdaniem oba rozwiązania są dobre, mimo że ja preferuję wstawki asemblerowe z zewn. plików.

GCC na pewno optymalizuje najlepiej. DICE nieco szybciej kompiluje i stąd zdobył moją sympatię.

Na postawie praktycznych przykładów, które podajesz, oraz tego, jak zorganizowałeś środowisko pracy z kompilatorem GCC, skłaniasz mnie ku temu kompilatorowi.

Kiedyś używałem go częściej. Teraz raczej DICE i SAS/C. Często w moim kodzie mam obsługę przerwań, odniesień do Blittera itp.

Na płycie CDPD 4, którą nabyłem parę lat temu, znajduje się starszy GCC i całkiem szybki.

Mam nadzieję, że nasze komentarze pomogą autorowi wątku w wyborze kompilatora i zorganizowania sobie środowiska.

Ostatnia aktualizacja: 19.02.2026 22:59:56 przez Hexmage960
Na stronie www.PPA.pl, podobnie jak na wielu innych stronach internetowych, wykorzystywane są tzw. cookies (ciasteczka). Służą ona m.in. do tego, aby zalogować się na swoje konto, czy brać udział w ankietach. Ze względu na nowe regulacje prawne jesteśmy zobowiązani do poinformowania Cię o tym w wyraźniejszy niż dotychczas sposób. Dalsze korzystanie z naszej strony bez zmiany ustawień przeglądarki internetowej będzie oznaczać, że zgadzasz się na ich wykorzystywanie.
OK, rozumiem