Pytanie podpisany jako domyślny w C


Po raz kolejny uczę lekcji, w której mam odpowiedzieć na pytania uczniów na temat C. Nie znam odpowiedzi na pytanie: czy istnieje uzasadnienie przyjęcia? signed jako domyślny modyfikator C? Można by pomyśleć unsigned był naturalnym wyborem. Czy to naprawdę była decyzja projektowa?


14
2017-09-04 01:25


pochodzenie


Samo "uzasadnienie" nie jest całkowicie poprawne. Dla zwykłego char, nie zawsze jest signed. - Eric Z
Dlaczego niepodpisane int byłoby bardziej naturalne? Myślę, że większość problemów z prawdziwego świata dotyczy zarówno wartości pozytywnych, jak i negatywnych. - jxh
@jxh Co ważniejsze, radzimy sobie z najbardziej realnymi problemami mały liczby - czyli liczby względnie blisko 0. Myślę, że większość osób w większości przypadków jest znacznie bardziej potrzebna niższa (lub przynajmniej bliska) 0, wtedy będą potrzebować liczb większych niż (lub nawet bliskich) MAX_INT. Podpisane liczby zachowują górny i dolny margines tak daleko od najczęściej używanych liczb, jak to możliwe. - Darrel Hoffman


Odpowiedzi:


Pod względem standard (ponieważ twoje pytanie jest oznaczone jako takie), signed został oznaczony jako domyślny, ponieważ tak było w przypadku implementacji C, które nastąpiły przed standard.

Pierwotne mandaty zgodne z normą ANSI / ISO polegały na kodyfikacji istniejącej praktyki, zamiast na tworzeniu nowego języka. Dlatego najważniejszym czynnikiem było zachowanie przedstandardowych implementacji, zgodnie z racjonalnym dokumentem:

Oryginalna karta X3J11 wyraźnie nakazała kodyfikację wspólnej istniejącej praktyki, a Komitet C89 utrzymał szybki precedens wszędzie tam, gdzie było to jasne i jednoznaczne.

Zdecydowana większość języka zdefiniowanego przez C89 była dokładnie taka sama jak zdefiniowana w Dodatku A pierwszej edycji Programu C przez Briana Kernighana i Dennisa Ritchie, i jak to było w prawie wszystkich tłumaczach C tego czasu. (Dokument ten jest dalej nazywany K & R.)

Jeśli chcesz dowiedzieć się, dlaczego preferowane są standardowe wersje signedprawdopodobnie będziesz musiał zajrzeć do architektury urządzeń PDP-n, dla których pierwotnie opracowano UNIX i C.

The Historia C strona to pokazuje unsigned w rzeczywistości był względnie późnym językiem, który pojawił się w połowie lat siedemdziesiątych:

W latach 1973-1980 język rósł nieco: struktura typu zyskała niepodpisane, długie, połączone i wyliczeniowe typy, a struktury stały się obiektami pierwszej klasy (brakowało tylko zapisu literałów).


15
2017-09-04 01:28



Hah. To interesujące. Pochylam się nad tą odpowiedzią, ale zauważ, że wciąż trochę to pytanie nasuwa: dlaczego poprzednie implementacje C mają signed jako domyślny? - Dervin Thunk
@Dervin, dlaczego nie? signed typ jest odpowiedni zarówno dla wartości dodatnich, jak i ujemnych, które są używane w życiu codziennym. - Eric Z
@Eric, racja, po prostu myślałem, że modyfikatory pojawiły się w tym samym czasie (co było błędem przypuszczać), więc gdybym był na etapie projektowania języka, zrobiłbym char unsigned i poprosiłbym programistę, aby powiedział ja wyraźnie chciałem inaczej. Historia jest bardzo interesująca! - Dervin Thunk
Według Wikipedii, C zostało opracowane dla PDP-7, ale jestem pewien, że K & R pracowało na wcześniejszych komputerach i było pod silnym wpływem języka BCPL. - Dervin Thunk
@Dervin, tak, jako jedna z niewielu żyjących małp kodowych, która pracowała i implementowała kompilatory BCPL :-), podobieństwa znacznie przewyższają różnice (przynajmniej na początku C). Ale był to piękny język na swój czas i umieszczam tam MartinR z dmr. I to było pierwotnie PDP7, tak, ale wkrótce musieli przenieść je na inne maszyny, w tym duże żelazko IBM. - paxdiablo


Chodzi głównie o kompatybilność wsteczną i pochodzenie C z wcześniejszych języków, które nie mogły w łatwy sposób obsługiwać zarówno liczb całkowitych podpisanych, jak i bez znaku.

C został wyprowadzony ze starszego języka o nazwie B, który wywodził się z jeszcze starszego języka o nazwie BCPL (który był uproszczoną wersją CPL).

BCPL było w dużej mierze bez typu język. Deklaracja zmiennych nie określała rodzaju obiektu; raczej operacja na danej zmiennej traktowałaby ją tak, jakby była danego typu.

Operatorzy BCPL +, -, *, /, i REM traktowali swoje operandy jako podpisany liczby całkowite i przyniosły wyniki całkowite.

Jeśli BCPL obsługuje liczby całkowite bez znaku, to albo musiałby mieć inny zestaw operatorów niepodpisanych operandów, albo nie byłby w stanie w ogóle reprezentować liczb ujemnych. (Należy pamiętać, że BCPL nie obsługiwała zmiennoprzecinkowej).

Składnia B była zupełnie inna od BCPL (i bliżej C), ale zachowała wiele z tej samej semantyki. W szczególności zmienne i funkcje były domyślnie typu całkowitego - i nie było unsigned słowo kluczowe.

Wczesne C, oparte na B, również nie miało unsigned słowo kluczowe. Miał tylko cztery podstawowe typy liczbowe: char, int, float, i double. (unsigned został dodany wraz z long, union, i enum, jakiś czas pomiędzy 1973 a 1980.) Biorąc pod uwagę słabo napisaną naturę języka, programiści czasami używali wskaźników, gdy potrzebowali niepodpisanej arytmetyki.

"Cecha", którą jednostka bez zadeklarowanego typu jest niejawnie typu int został zachowany w C aż do normy ISO z 1999 r. ostatecznie usunął "ukryty" int"zasada.

Ponadto, liczby całkowite ze znakiem są po prostu większe przydatny niż typy bez znaku. Zdolność do reprezentowania wartości ujemnych może być niezwykle wygodna. Biorąc pod uwagę typową semantykę zawiasów, błąd w niepodpisanym odejmowaniu dwóch małych wartości może dać ogromną wartość dodatnią (3 - 4 == 65535 na przykład dla 16-bitowego typu bez podpisu). Nawet w dziedzinie programowania systemów, która jest głównym celem wszystkich tych języków, czasami konieczne jest przedstawienie wartości ujemnych (na przykład zmiana w pewnej ilości).

Referencje:


5
2017-09-04 02:29





Według Rozwój języka C., pojęcie niepodpisane było rozszerzeniem języka, gdy dodawano do niego elementy w latach 1973-1980. Chociaż nie zostało to wyraźnie powiedziane, narracja sugeruje, że nie została wprowadzona do 1977 r. (zob. Ruchliwość, ust. 3).

Tak więc domyślne podpisanie wynikało z faktu, że język początkowo miał tylko podpisane typy.


3
2017-09-04 01:41





Domyślna sygnatura z char nie jest zdefiniowany przez język. Jest to określone przez implementację. Niektóre procesory mają bardziej naturalny znak char, a inne są w naturalny sposób niepodpisane.


0
2017-09-04 01:28



co masz na myśli "naturalnie" podpisane? - Dervin Thunk
@DervinThunk: Naturalność instrukcji rozszerzania 8-bitowej ilości do 16-bitowej lub większej ma określone założenia, zwłaszcza procesory przed około 1985 roku. Aby wypromować znak char w int nienaturalny kierunek wymaga dodatkowych instrukcji, aby tak się stało. The naturalny kierunek wymaga tylko jednej instrukcji. - wallyk
@Wallyk, czy jesteś pewien, że standard nie wymaga podpisu zwykłego int? Pamiętam, że standard wymusza najmniejszy zakres wartości, które mogą być reponsented przez int. Widzieć stackoverflow.com/questions/6155784/... - Eric Z
To odnosi się tylko do zwykłego char. Równina int jest zawsze podpisany (z wyjątkiem pól bitowych, gdzie zwykły int ma sygnatury określone przez implementację). - Keith Thompson
@EricZ: Myślałem, że pierwotne pytanie dotyczyło domyślnej sygnatury char. Wyjaśniłem to wyraźnie w mojej odpowiedzi. - wallyk


unsigned semantyka jest prostsza: modulo base-2n bez wyjątków. Ale nie zakładaj, co n to: rozmiar zakresu nie musi być równy rozmiarowi odpowiedniego podpisanego typu.

Jedynym wymaganiem jest to, że wszystkie pozytywne podpisane wartości mogą być również reprezentowane przez odpowiedni niepodpisany typ.

Jedna ważna implementacja unsigned byłoby użyć arytmetyki podpisanej z dopełnieniem dwóch uzupełnień i wyzerować bit znaku po każdej operacji. Jest mało prawdopodobne, aby pojawił się w realnym życiu, ale maszyny z arytmetyką nie uzupełniającą się przez dwa mogą mieć więcej problemów z pominięciem logiki liczb ujemnych.

W praktyce liczby ujemne są podstawową cechą każdej platformy sprzętowej, ale umiejętność traktowania całego rejestru jako liczby dodatniej jest po prostu wisienką na torcie. C jest zaprojektowany tak, aby owijać najbardziej ciasno wokół najbardziej wydajnych części sprzętu.


0
2017-09-04 04:21