Jakie platformy mają coś innego niż 8-bitowe znaki?


136

Od czasu do czasu ktoś na SO wskazuje, że char(inaczej „bajt”) niekoniecznie musi mieć 8 bitów .

Wygląda na to, że 8-bitowe charjest prawie uniwersalne. Pomyślałbym, że w przypadku platform głównego nurtu konieczne jest posiadanie 8-bitowego, charaby zapewnić jego żywotność na rynku.

Jakie platformy używają obecnie i w przeszłości platformy, charktóra nie ma 8 bitów i dlaczego miałyby różnić się od „normalnych” 8 bitów?

Pisząc kod i myśląc o obsłudze wielu platform (np. Dla bibliotek ogólnego użytku), na co warto zwrócić uwagę na platformach innych niż 8-bitowe char?

W przeszłości natknąłem się na kilka procesorów DSP Analog Devices, które charmają 16 bitów. Podejrzewam, że procesory DSP są trochę niszową architekturą. (Z drugiej strony, w tamtym czasie ręcznie kodowany asembler z łatwością pokonał to, co mogły zrobić dostępne kompilatory C, więc tak naprawdę nie miałem zbyt dużego doświadczenia z C na tej platformie).


9
Seria CDC Cyber ​​miała kodowanie 6/12 bitów. Najpopularniejsze postacie miały 6 bitów. Pozostałe znaki miały 12 bitów.
Thomas Matthews,

2
PDP-11 go przybił. Pogląd, że znak można zakodować w znaku, jest poważnie przestarzały.
Hans Passant

7
„PDP-11 załatwił sprawę” - Masz na myśli to, że C został po raz pierwszy zaimplementowany dla PDP-11 z 8-bitowymi bajtami? Ale C został następnie zaimplementowany dla maszyn Honeywell z 9-bitowymi bajtami. Zobacz wersję K&R 1. Również pytanie zadane o znak (tj. Bajt), a nie o znak (jeden lub więcej bajtów koduje coś, o co nie pytano).
Programista Windows,

6
DEC-10 i DEC-20 miały 36-bitowe słowa. Pięć 7-bitowych znaków ASCII na słowo było dość powszechne. Wykorzystano również sześć 6-bitowych znaków.
David R Tribble

3
@CraigMcQueen: Jeśli dobrze pamiętam, mikrokontrolery CodeVision dla Atmel pozwalają wybrać rozmiar znaku
vsz

Odpowiedzi:


80

charjest również 16-bitowy w procesorach DSP Texas Instruments C54x, które pojawiły się na przykład w OMAP2. Istnieją inne procesory DSP z 16 i 32 bitamichar . Myślę, że słyszałem nawet o 24-bitowym DSP, ale nie pamiętam co, więc może sobie to wyobraziłem.

Inną kwestią jest to, że POSIX wymaga CHAR_BIT == 8. Więc jeśli używasz POSIX, możesz to założyć. Jeśli ktoś później będzie musiał przenieść twój kod do prawie implementacji POSIX, tak się składa, że ​​ma funkcje, których używasz, ale inny rozmiar char, to jego pech.

Ogólnie rzecz biorąc, myślę, że prawie zawsze łatwiej jest obejść ten problem niż o nim pomyśleć. Po prostu wpisz CHAR_BIT. Jeśli chcesz mieć dokładnie 8-bitowy typ, użyj int8_t. Twój kod głośno nie będzie się kompilował na implementacjach, które go nie zapewniają, zamiast dyskretnie używać rozmiaru, którego się nie spodziewałeś. Przynajmniej, gdybym trafił na przypadek, w którym miałbym dobry powód, żeby to założyć, to bym to potwierdził.


2
Procesory DSP TI C62xx i C64xx również mają 16-bitowe znaki. (uint8_t nie jest zdefiniowany na tej platformie).
myron-semack

7
Wiele procesorów DSP do przetwarzania dźwięku to maszyny 24-bitowe; BelaSigna DSP z On Semi (po kupili AMI pół); DSP56K / Symphony audio DSP z Freescale (po ich wydzielona z firmy Motorola).
David Cary,

2
@msemack C64xx ma sprzęt dla 8/16/32/40 i 8
bitowego

4
Zamiast assert()(jeśli to miałeś na myśli), użyłbym #if CHAR_BIT != 8... #error "I require CHAR_BIT == 8"...#endif
Keith Thompson

1
@KeithThompson Czy jest jakiś powód, aby nie używać static_assert()?
Qix - MONICA ZOSTAŁA POMYŚLNA

37

Pisząc kod i myśląc o obsłudze wielu platform (np. Dla bibliotek ogólnego użytku), na co warto zwrócić uwagę na platformach z znakami innymi niż 8-bitowe?

Nie chodzi o to, że „warto się nad czymś zastanowić”, ale o granie według zasad. Na przykład w C ++ standard mówi, że wszystkie bajty będą miały „co najmniej” 8 bitów. Jeśli Twój kod zakłada, że ​​bajty mają dokładnie 8 bitów, naruszasz standard.

To może wydawać się teraz głupie - „ oczywiście wszystkie bajty mają 8 bitów!”, Słyszę, jak mówisz. Ale wielu bardzo inteligentnych ludzi oparło się na założeniach, które nie były gwarancją, a potem wszystko się zepsuło. Historia jest pełna takich przykładów.

Na przykład większość deweloperów wczesnych lat 90. założyło, że określone opóźnienie taktowania procesora bez operacji, zajmujące stałą liczbę cykli, zajmie stałą ilość czasu, ponieważ większość procesorów konsumenckich miała mniej więcej taką samą moc. Niestety komputery bardzo szybko stały się szybsze. To spowodowało powstanie pudełek z przyciskami „Turbo” - których celem, jak na ironię, było spowolnienie komputera, aby gry wykorzystujące technikę opóźnienia czasowego mogły być odtwarzane z rozsądną prędkością.


Jeden komentator zapytał, gdzie w standardzie jest napisane, że znak musi mieć co najmniej 8 bitów. Jest w sekcji 5.2.4.2.1 . Ta sekcja definiuje CHAR_BITliczbę bitów w najmniejszej adresowalnej encji i ma domyślną wartość 8. Mówi się również:

Ich wartości zdefiniowane w ramach realizacji muszą być równe lub większe pod względem wielkości (wartość bezwzględna) od przedstawionych, z tym samym znakiem.

Zatem każda liczba równa 8 lub wyższa nadaje się do zastąpienia przez implementację do CHAR_BIT.


6
Nie widziałem przycisku Turbo od co najmniej 20 lat - czy naprawdę myślisz, że jest to związane z pytaniem?
Mark Ransom

29
@Mark Ransom: O to właśnie chodzi. Deweloperzy często opierają się na założeniach, które w tej chwili wydają się prawdziwe, ale są znacznie bardziej chwiejne, niż się początkowo wydaje. (Nie mogę zliczyć, ile razy popełniłem ten błąd!) Przycisk Turbo powinien być bolesnym przypomnieniem, aby nie robić niepotrzebnych założeń, a już na pewno nie robić założeń, których nie gwarantuje standard językowy, tak jakby były niezmienne fakty.
John Feminella,

1
Czy mógłbyś wskazać na umieszczenie w C ++ Standard, który mówi, że bye ma co najmniej 8 bitów? Jest to powszechne przekonanie, jednak osobiście nie udało mi się go znaleźć w standardzie. Jedyne, co znalazłem w standardzie, to to, które znaki muszą być reprezentowane przez charjest ich więcej niż 64, ale mniej niż 128, więc wystarczyłoby 7 bitów.
Adam Badura,

6
Sekcja 18.2.2 odwołuje się do standardu C. W standardzie C jest to sekcja 7.10, a następnie sekcja 5.4.2.4.1. Strona 22 w standardzie C.
Programista Windows,

2
Więc inne odpowiedzi i komentarze wspominają o maszynach z 5-bitowymi, 6-bitowymi i 7-bitowymi bajtami. Czy to oznacza, że ​​nie możesz uruchomić programu w C na tej maszynie, który jest zgodny ze standardem?
Jerry Jeremiah,

34

Maszyny o architekturze 36-bitowej mają 9-bitowe bajty. Według Wikipedii maszyny o architekturze 36-bitowej obejmują:

  • Digital Equipment Corporation PDP-6/10
  • IBM 701/704/709/7090/7094
  • UNIVAC 1103 / 1103A / 1105/1100/2200,

7
Również maszyny Honeywell, takie jak być może druga maszyna, w której zaimplementowano C. Zobacz wersję K&R 1.
programista Windows,

5
Właściwie, 10 grudnia miał również 6-bitowe znaki - można było spakować 6 z nich w 36-bitowe słowo (mówił były programista z 10 grudnia)

2
DEC-20 używał pięciu 7-bitowych znaków ASCII na 36-bitowe słowo w TOPS-20 O / S.
David R Tribble

3
Ten żart został faktycznie zaimplementowany do obsługi Unicode w tej architekturze.
Joshua,

9
Wyobrażam sobie, że powodem, dla którego kiedykolwiek używano liczby ósemkowej, było to, że 3 cyfry ósemkowe zgrabnie reprezentują 9-bitowy bajt, tak jak zwykle używamy dziś szesnastkowego, ponieważ dwie cyfry szesnastkowe dokładnie reprezentują 8-bitowy bajt.
bames53

18

Kilka z nich jestem świadomy:

  • DEC PDP-10: zmienne, ale najczęściej 7-bitowe znaki pakowane po 5 na słowo 36-bitowe lub 9-bitowe, po 4 na słowo
  • Kontrolery danych mainframe (CDC-6400, 6500, 6600, 7600, Cyber ​​170, Cyber ​​176 itp.) 6-bitowe znaki, pakowane po 10 na 60-bitowe słowo.
  • Komputery mainframe Unisys: 9 bitów / bajt
  • Windows CE: po prostu w ogóle nie obsługuje typu `char` - zamiast tego wymaga 16-bitowego wchar_t

2
@ephemient: Jestem prawie pewien, że istniał przynajmniej jeden (przedstandardowy) kompilator C dla PDP-10 / DecSystem 10 / DecSystem 20. Byłbym bardzo zaskoczony kompilatorem C dla mainframe'ów CDC (były używany głównie do pracy numerycznej, więc kompilator Fortran był tam najważniejszy). Jestem prawie pewien, że inni mają kompilatory C.
Jerry Coffin

3
Czy kompilator Windows CE naprawdę w ogóle nie obsługiwał tego chartypu? Wiem, że biblioteki systemowe obsługiwały tylko szerokie wersje funkcji, które pobierają ciągi znaków, i że przynajmniej niektóre wersje WinCE usunęły funkcje ciągów ANSI, takie jak strlen, aby uniemożliwić ci obsługę łańcuchów znaków. Ale czy naprawdę w ogóle nie miał typu char? Co to było sizeof(TCHAR)? Jaki typ powrócił Malloc? Jak bytezaimplementowano typ Java ?
Steve Jessop,

10
Windows CE obsługuje znak, który jest bajtem. Zobacz komentarz Craiga McQueena na temat odpowiedzi Richarda Penningtona. Bajty są potrzebne tak samo w Windows CE, jak wszędzie indziej, bez względu na ich rozmiary wszędzie indziej.
Programista Windows,

2
Istnieją (były?) Przynajmniej dwie implementacje języka C dla PDP-10: KCC i port gcc ( pdp10.nocrew.org/gcc ).
AProgrammer

3
Standard C nie dopuszczałby 7-bitowych znaków spakowanych po 5 na 36-bitowe słowo (jak wspomniałeś w przypadku PDP-10), ani też nie dopuszczałby 6-bitowych znaków, jak wspomniałeś w przypadku mainframe'ów z danymi kontrolnymi. Zobacz parashift.com/c++-faq-lite/intrinsic-types.html#faq-26.6
Ken Bloom,

15

Nie ma czegoś takiego jak całkowicie przenośny kod. :-)

Tak, mogą istnieć różne rozmiary bajtów / znaków. Tak, mogą istnieć implementacje C / C ++ dla platform z bardzo nietypowymi wartościami CHAR_BITiUCHAR_MAX . Tak, czasami można napisać kod niezależny od rozmiaru znaku.

Jednak prawie każdy prawdziwy kod nie jest samodzielny. Np. Możesz pisać kod, który wysyła binarne wiadomości do sieci (protokół nie jest ważny). Możesz zdefiniować struktury, które zawierają niezbędne pola. Wtedy musisz to serializować. Samo binarne kopiowanie struktury do bufora wyjściowego nie jest przenośne: generalnie nie znasz ani kolejności bajtów dla platformy, ani wyrównania elementów struktury, więc struktura po prostu przechowuje dane, ale nie opisuje sposobu, w jaki dane powinny być serializowane .

Dobrze. Możesz wykonywać transformacje kolejności bajtów i przenosić składowe struktury (np. uint32_tLub podobne) za pomocą memcpydo bufora. Dlaczego memcpy? Ponieważ istnieje wiele platform, na których nie można zapisać 32-bitowego (16-bitowego, 64-bitowego - bez różnicy), gdy adres docelowy nie jest prawidłowo wyrównany.

Tak więc wiele już zrobiłeś, aby zapewnić przenośność.

A teraz ostatnie pytanie. Mamy bufor. Dane z niego przesyłane są do sieci TCP / IP. Taka sieć przyjmuje 8-bitowe bajty. Pytanie brzmi: jakiego typu powinien być bufor? Jeśli twoje znaki są 9-bitowe? Jeśli są 16-bitowe? 24? Może każdy znak odpowiada jednemu 8-bitowemu bajtowi wysłanemu do sieci, a używanych jest tylko 8 bitów? A może wiele bajtów sieciowych jest pakowanych w znaki 24/16/9-bitowe? To jest pytanie i trudno uwierzyć, że istnieje jedna odpowiedź, która pasuje do wszystkich przypadków. Wiele rzeczy zależy od implementacji gniazda na platformie docelowej.

Więc o czym mówię. Zwykle do pewnego stopnia kod można stosunkowo łatwo przenieść do postaci przenośnej . Jest to bardzo ważne, jeśli spodziewasz się używania kodu na różnych platformach. Jednak poprawa przenośności wykraczająca poza ten środek to rzecz, która wymaga dużego wysiłku i często daje niewiele , ponieważ rzeczywisty kod prawie zawsze zależy od innego kodu (implementacja gniazda w powyższym przykładzie). Jestem pewien, że dla około 90% kodu możliwość pracy na platformach z bajtami innymi niż 8-bitowe jest prawie bezużyteczna, gdyż wykorzystuje środowisko związane z 8-bitami. Po prostu sprawdź rozmiar bajtu i przeprowadź asercję czasu kompilacji. Prawie na pewno będziesz musiał wiele przepisać na bardzo nietypową platformę.

Ale jeśli Twój kod jest wysoce „samodzielny” - dlaczego nie? Możesz napisać to w sposób, który pozwala na różne rozmiary bajtów.


4
Jeśli przechowuje się jeden oktet na unsigned charwartość, nie powinno być problemów z przenoszeniem, chyba że kod używa sztuczek aliasingu zamiast przesunięć w celu konwersji sekwencji oktetów na / z większych typów całkowitych. Osobiście uważam, że standard C powinien definiować elementy wewnętrzne do pakowania / rozpakowywania liczb całkowitych z sekwencji krótszych typów (najczęściej char) przechowujących stałą gwarantowaną dostępną liczbę bitów na sztukę (8 na unsigned char, 16 na unsigned shortlub 32 na unsigned long).
supercat



5

Na przykład języki programowania C i C ++ definiują bajt jako „adresowalną jednostkę danych wystarczająco dużą, aby pomieścić dowolny element podstawowego zestawu znaków środowiska wykonawczego” (klauzula 3.6 standardu C). Ponieważ typ danych całkowitych typu C char musi zawierać co najmniej 8 bitów (klauzula 5.2.4.2.1), bajt w C może przechowywać co najmniej 256 różnych wartości. Różne implementacje C i C ++ definiują bajt jako 8, 9, 16, 32 lub 36 bitów

Cytat z http://en.wikipedia.org/wiki/Byte#History

Nie jestem pewien co do innych języków.

http://en.wikipedia.org/wiki/IBM_7030_Stretch#Data_Formats

Definiuje bajt na tym komputerze o zmiennej długości


1
„Nie jestem pewien co do innych języków” - historycznie większość języków pozwalała architekturze maszyny na definiowanie własnego rozmiaru bajtów. Właściwie historycznie podobnie C, dopóki standard nie ustalił dolnej granicy na 8.
Programista Windows,

4

Rodzina DEC PDP-8 miała 12-bitowe słowo, chociaż zwykle używałeś 8-bitowego ASCII do wyjścia (głównie na Teletype). Jednak był też 6-bitowy kod znaków, który pozwalał zakodować 2 znaki w jednym 12-bitowym słowie.


3

Po pierwsze, znaki Unicode są dłuższe niż 8-bitowe. Jak ktoś wcześniej wspomniał, specyfikacja C definiuje typy danych według ich minimalnych rozmiarów. Użyj sizeofi wartości wlimits.h jeśli chcesz przesłuchać typy danych i dowiedzieć się, jaki dokładnie mają rozmiar dla Twojej konfiguracji i architektury.

Z tego powodu staram się trzymać typów danych, na przykład uint16_tgdy potrzebuję typu danych o określonej długości bitowej.

Edycja: Przepraszamy, początkowo źle odczytałem twoje pytanie.

Specyfikacja C mówi, że charobiekt jest „wystarczająco duży, aby przechowywać dowolny element zestawu znaków wykonania”. limits.hpodaje minimalny rozmiar 8 bitów, ale definicja pozostawia maksymalny rozmiar charotwarcia.

W związku z tym a charjest co najmniej tak długi, jak największy znak z zestawu wykonawczego Twojej architektury (zazwyczaj zaokrąglany w górę do najbliższej 8-bitowej granicy). Jeśli twoja architektura ma dłuższe rozkazy, twójchar rozmiar może być dłuższy.

Historycznie rzecz biorąc, kod operacyjny platformy x86 miał długość jednego bajtu, więc charpoczątkowo był to wartość 8-bitowa. Obecne platformy x86 obsługują opkody dłuższe niż jeden bajt, ale charjest on utrzymywany na 8 bitach, ponieważ od tego są uzależnieni programiści (i duże ilości istniejącego kodu x86).

Myśląc o obsłudze wielu platform, skorzystaj z typów zdefiniowanych w stdint.h. Jeśli korzystasz (na przykład) na uint16_t, wtedy można mieć pewność, że wartość ta jest niepodpisany wartość 16-bitowa na dowolnej architekturze, czy odpowiadający wartości 16-bitowej do char, short, int, lub coś innego. Większość ciężkiej pracy została już wykonana przez ludzi, którzy napisali Wasze biblioteki kompilatorów / standardowych.

Jeśli potrzebujesz znać dokładny rozmiar a, charponieważ wykonujesz jakieś operacje sprzętowe niskiego poziomu, które tego wymagają, zwykle używam typu danych, który jest wystarczająco duży, aby pomieścić a charna wszystkich obsługiwanych platformach (zwykle wystarcza 16 bitów) i uruchamiam wartość poprzez convert_to_machine_charprocedurę, gdy potrzebuję dokładnej reprezentacji maszyny. W ten sposób kod specyficzny dla platformy jest ograniczony do funkcji interfejsu i przez większość czasu mogę używać normalnego uint16_t.


2
Pytanie nie dotyczyło znaków (czy to Unicode, czy nie). Pytał o znak, który jest bajtem.
Programista Windows,

1
Ponadto zestaw znaków wykonania nie ma nic wspólnego z opkodami, jest to zestaw znaków używany podczas wykonywania, pomyśl o cross-kompilatorach.
ninjalj

„Historycznie rzecz biorąc, kod operacyjny platformy x86 miał długość jednego bajta”: jakie to słodkie. Historycznie rzecz biorąc , C został opracowany na PDP-11 (1972), na długo przed wynalezieniem x86 (1978).
Martin Bonner wspiera Monikę w

3

jaki rodzaj uwagi warto poświęcić platformom z znakami innymi niż 8-bitowe?

magiczne liczby pojawiają się np. podczas przesuwania;

większość z nich można obsłużyć w prosty sposób, używając CHAR_BIT i np. UCHAR_MAX zamiast 8 i 255 (lub podobnych).

miejmy nadzieję, że Twoja implementacja je definiuje :)

to są „typowe” problemy .....

inną pośrednią kwestią jest to, że masz:

struct xyz {
   uchar baz;
   uchar blah;
   uchar buzz; 
}

może to zająć „tylko” (w najlepszym przypadku) 24 bity na jednej platformie, ale może zająć np. 72 bity w innym miejscu .....

jeśli każdy uchar trzymał "flagi bitowe" i każdy uchar miał tylko 2 "znaczące" bity lub flagi, których aktualnie używasz, i zorganizowałeś je tylko w 3 uchary dla "przejrzystości", wtedy może to być stosunkowo "bardziej marnotrawne" np. platforma z 24-bitowymi ucharami .....

nic bitfieldów nie może rozwiązać, ale mają inne rzeczy, na które trzeba uważać ....

w tym przypadku tylko jedno wyliczenie może być sposobem na uzyskanie „najmniejszej” liczby całkowitej, której faktycznie potrzebujesz ....

może nie jest to prawdziwy przykład, ale takie rzeczy „ugryzły” mnie podczas przenoszenia / grania z jakimś kodem…

tylko fakt, że jeśli uchar jest trzykrotnie większy niż to, co jest "normalnie" oczekiwane, 100 takich struktur może marnować dużo pamięci na niektórych platformach ..... gdzie "normalnie" to nie jest wielka sprawa .... .

więc rzeczy nadal mogą być "zepsute" lub w tym przypadku "marnować dużo pamięci bardzo szybko" z powodu założenia, że ​​uchar jest "niezbyt marnotrawny" na jednej platformie w stosunku do dostępnej pamięci RAM, niż na innej platformie ... ..

problem może być bardziej widoczny, np. również w przypadku int, lub innych typów, np. masz strukturę, która wymaga 15 bitów, więc umieszczasz ją w int, ale na innej platformie int ma 48 bitów lub cokolwiek .... .

„normalnie” możesz podzielić to na 2 uchary, ale np. z 24-bitowym uchar potrzebujesz tylko jednego .....

więc wyliczenie może być lepszym rozwiązaniem „ogólnym” ...

zależy jednak od tego, w jaki sposób uzyskujesz dostęp do tych bitów :)

więc mogą istnieć "wady projektowe", które odwracają ich głowę ... nawet jeśli kod może nadal działać / działać dobrze, niezależnie od rozmiaru uchar lub uint ...

są takie rzeczy, na które trzeba uważać, mimo że w Twoim kodzie nie ma „magicznych liczb” ...

mam nadzieję, że to ma sens :)


1
...co? Jak myślisz, dlaczego enummoże być mniejszy niż inne rodzime typy? Czy wiesz, że domyślnie jest to ta sama pamięć, co int? „masz jakąś strukturę, która wymaga 15 bitów, więc umieszczasz ją w int, ale na innej platformie int ma 48 bitów lub cokolwiek .....” - więc #include <cstdint>zrób int16_tz tego największą szansę na zminimalizowanie użycia bitów . Naprawdę nie jestem pewien, co myślisz, że mówisz wśród tych wszystkich elips.
underscore_d

1

ints miały 16 bitów (pdp11 itp.). Przejście na architekturę 32-bitową było trudne. Ludzie są coraz lepsi: prawie nikt nie zakłada, że ​​wskaźnik będzie już pasował na długo (nie masz racji?). Lub zapisuj przesunięcia, sygnatury czasowe lub ...

8-bitowe znaki są już pewnym anachronizmem. Potrzebujemy już 32 bitów, aby pomieścić wszystkie zestawy znaków świata.


2
Prawdziwe. Nazwa charjest teraz nieco osobliwa w czasach Unicode. Bardziej interesują mnie jednostki 8-bitowe (oktety), gdy mam do czynienia z danymi binarnymi, np. Przechowywanie plików, komunikacja sieciowa. uint8_tjest bardziej przydatne.
Craig McQueen

3
Właściwie Unicode nigdy nie potrzebował pełnych 32 bitów. Pierwotnie planowali na 31 (zobacz oryginalną pracę UTF-8), ale teraz są zadowoleni z tylko 21 bitów . Prawdopodobnie zdali sobie sprawę, że nie byliby w stanie więcej wydrukować książki, gdyby faktycznie potrzebowali wszystkich 31 bitów: P
ja 22

2
@ me22, Unicode pierwotnie planowano na 16 bitów. „Znaki Unicode mają stałą szerokość 16 bitów, niezależnie od języka…” Unicode 1.0.0. unicode.org/versions/Unicode1.0.0/ch01.pdf .
Shannon Severance

1
ISO 10646 pierwotnie miał 31 bitów, a Unicode został połączony z ISO 10646, więc może być nierozsądne stwierdzenie, że Unicode miał 31 bitów, ale nie jest to tak naprawdę nieprawdziwe. Zauważ, że w rzeczywistości nie drukują już pełnych tabel kodu.
prosfilaes
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.