Jedyną książką referencyjną C, której ufam, jest „C: A Reference Manual” Harbison & Steele ( careferencemanual.com ). Oczywiście standard jest ostatnim słowem, ale nie jest zbyt czytelny i podaje tylko najmniejsze informacje o zastosowaniach przedstandardowych i powszechnych (tj. POSIX), które są poza standardem. Harbison & Steele jest całkiem czytelny, szczegółowy i prawdopodobnie bardziej poprawny niż większość odniesień. Jednak nie jest to również samouczek, więc jeśli jesteś na początkowym etapie nauki, prawdopodobnie nie jest to świetna rzecz.
Michael Burr
15
Myślę, że książka, którą czytasz, to C: The Complete Reference autorstwa Herberta Schildta. Z recenzji tej książki ( accu.informika.ru/accu/bookreviews/public/reviews/c/c002173.htm ): Nie zamierzam polecać tej książki (zbyt wielu z was przykłada zbyt dużą wagę do moich opinii), ale Nie sądzę, by zasługiwała na taką samą potępienie, jaka została słusznie rzucona na niektóre jego inne prace. Jak mówi Michael, dużo lepszym odniesieniem jest Harbison & Steele .
Alok Singhal
Moje dwa centy tutaj: Ponieważ charmoże być bez znaku, z reguły użyj intdo odczytania wartości, używając getchar(), która może zwrócić EOF. EOFjest zwykle definiowana jako -1lub inna wartość ujemna, której przechowywanie w pliku unsignednie jest tym, czego chcesz. Oto deklaracja: extern int getchar();BTW, to zalecenie pochodzi również z książki „C: A Reference Manual”.
Maxim Chetrusca
6
Jedynym odniesieniem C, któremu ufam, jest ISO / IEC 9899: 2011 :-)
Jeff
3
@MaxChetrusca Dobra rada, ale kiepskie uzasadnienie: nawet w charprzypadku podpisanego przypadku musiałbyś użyć intdo przechowywania wartości zwracanej.
Antti Haapala
Odpowiedzi:
204
Książka jest zła. Standard nie określa, czy zwykły charjest podpisany, czy nie.
W rzeczywistości, średnia definiuje trzy różne typy: char, signed chari unsigned char. Jeśli #include <limits.h>przyjrzysz się CHAR_MIN, a następnie przyjrzysz się , możesz dowiedzieć się, czy zwykły charjest równy signedlub unsigned(jeśli CHAR_MINjest mniejszy niż 0 lub równy 0), ale nawet wtedy te trzy typy są różne, jeśli chodzi o standard.
Zwróć uwagę, że charjest to wyjątkowe w ten sposób. Jeśli deklarujesz zmienną, ponieważ intjest to 100% równoważne zadeklarowaniu jej jako signed int. Dotyczy to zawsze wszystkich kompilatorów i architektur.
@Alok: to samo nie jest prawdą dla niektórych innych typów danych, na przykład intoznacza signed intzawsze, prawda? Poza chartym, w jakich innych typach danych występuje ten sam błąd C?
Lazer,
8
@eSKay: tak, charto jedyny typ, który może być podpisany lub niepodpisany. intjest odpowiednikiem signed intna przykład.
Alok Singhal
28
Jest tego histeryczny, hm, historyczny powód - na początku życia C „standard” został przerzucony co najmniej dwa razy, a niektóre popularne wczesne kompilatory skończyły w ten sposób, a inne w drugą.
Hot Licks
9
@AlokSinghal: Jest również zdefiniowane przez implementację, czy pole bitowe typu intjest podpisane czy nie.
Keith Thompson
@KeithThompson dzięki za korektę. Zwykle zapominam o niektórych szczegółach dotyczących typów pól bitowych, ponieważ nie używam ich zbyt często.
Alok Singhal
67
Jak wskazuje Alok , standard pozostawia to w gestii implementacji.
Dla gcc, wartość domyślna jest podpisana, ale możesz to zmienić za pomocą -funsigned-char. uwaga: dla gcc w Android NDK, domyślną wartością jest unsigned . Możesz również wyraźnie poprosić o podpisane znaki za pomocą -fsigned-char.
Na MSVC wartość domyślna jest podpisana, ale można ją zmodyfikować za pomocą /J.
Ciekawe, że opis Schildta nie pasuje do zachowania MSVC, ponieważ jego książki są zwykle skierowane do użytkowników MSVC. Zastanawiam się, czy MS zmieniło w pewnym momencie domyślne?
Michael Burr,
1
Myślałem, że to nie jest zależne od kompilatora, ale od platformy. Myślałem, że znak char został pozostawiony jako trzeci typ „znakowego typu danych”, aby dostosować się do tego, co systemy w tamtym czasie używały jako znaki drukowalne.
Spidey
10
Dokumentacja GCC mówi, że jest to zależne od maszyny: " Każdy rodzaj maszyny ma domyślne ustawienie tego, jaki powinien być znak. Jest albo domyślnie jak bez znaku lub domyślnie jak znak ze znakiem. "
Deduplicator,
1
Czy możesz podać źródło swojej notatki, że w systemie Android domyślną wartością jest niepodpisany znak?
phlipsy
1
@Spidey standard C nie rozróżnia kompilatorów, platform i architektur procesorów. Po prostu grupuje je wszystkie razem w ramach „realizacji”.
plugwash
35
C99 N1256 szkic 6.2.5 / 15 „Typy” ma do powiedzenia na temat podpisu typu char:
W implementacji należy zdefiniować znak char, który ma taki sam zakres, reprezentację i zachowanie, jak znak ze znakiem lub bez znaku.
oraz w przypisie:
CHAR_MIN, zdefiniowane w <limits.h>, będzie miało jedną z wartości 0lub SCHAR_MIN, i można to wykorzystać do rozróżnienia tych dwóch opcji. Niezależnie od dokonanego wyboru, charjest typem odrębnym od dwóch pozostałych i nie jest kompatybilny z żadnym.
Według książki The C Programming Language autorstwa Dennisa Ritchiego, która jest de facto standardową książką dla ANSI C, zwykłe znaki ze znakiem lub bez znaku zależą od maszyny, ale znaki drukowalne są zawsze dodatnie.
Niekoniecznie jest tak, że znaki do druku są zawsze pozytywne. Standard C gwarantuje, że wszyscy członkowie podstawowego zestawu znaków wykonania mają wartości nieujemne.
Keith Thompson
7
Zgodnie ze standardem C podpisanie zwykłego znaku jest „zdefiniowane w implementacji”.
Ogólnie rzecz biorąc, realizatorzy wybrali ten, który był bardziej efektywny do wdrożenia w ich architekturze. W systemach x86 znak jest zwykle podpisany. W systemach z ramieniem jest zwykle niepodpisany (wyjątkiem jest Apple iOS).
@plugwash Twoja odpowiedź została prawdopodobnie odrzucona, ponieważ Tim Post zgubił klucze . Poważnie jednak, nie powinieneś martwić się o jeden głos przeciw, o ile masz pewność, że Twoja odpowiedź jest prawidłowa (tak jest w tym przypadku). Kilka razy zdarzyło mi się, że moje posty zostały odrzucone bez ważnego powodu. Nie martw się tym, czasami ludzie po prostu robią dziwne rzeczy.
Kaczor Donald
1
Dlaczego podpisany znak jest bardziej wydajny na platformie x86? Jakieś źródła?
martinkunev
2
Zgodnie z „The C ++ Programming Language” Bjarne Stroustrup, char„implementacja zdefiniowana”. Może to być signed charlub w unsigned charzależności od implementacji. Możesz sprawdzić, czy charjest podpisany, czy nie, używając std::numeric_limits<char>::is_signed.
char
może być bez znaku, z reguły użyjint
do odczytania wartości, używającgetchar()
, która może zwrócićEOF
.EOF
jest zwykle definiowana jako-1
lub inna wartość ujemna, której przechowywanie w plikuunsigned
nie jest tym, czego chcesz. Oto deklaracja:extern int getchar();
BTW, to zalecenie pochodzi również z książki „C: A Reference Manual”.char
przypadku podpisanego przypadku musiałbyś użyćint
do przechowywania wartości zwracanej.Odpowiedzi:
Książka jest zła. Standard nie określa, czy zwykły
char
jest podpisany, czy nie.W rzeczywistości, średnia definiuje trzy różne typy:
char
,signed char
iunsigned char
. Jeśli#include <limits.h>
przyjrzysz sięCHAR_MIN
, a następnie przyjrzysz się , możesz dowiedzieć się, czy zwykłychar
jest równysigned
lubunsigned
(jeśliCHAR_MIN
jest mniejszy niż 0 lub równy 0), ale nawet wtedy te trzy typy są różne, jeśli chodzi o standard.Zwróć uwagę, że
char
jest to wyjątkowe w ten sposób. Jeśli deklarujesz zmienną, ponieważint
jest to 100% równoważne zadeklarowaniu jej jakosigned int
. Dotyczy to zawsze wszystkich kompilatorów i architektur.źródło
int
oznaczasigned int
zawsze, prawda? Pozachar
tym, w jakich innych typach danych występuje ten sam błądC
?char
to jedyny typ, który może być podpisany lub niepodpisany.int
jest odpowiednikiemsigned int
na przykład.int
jest podpisane czy nie.Jak wskazuje Alok , standard pozostawia to w gestii implementacji.
Dla gcc, wartość domyślna jest podpisana, ale możesz to zmienić za pomocą
-funsigned-char
. uwaga: dla gcc w Android NDK, domyślną wartością jest unsigned . Możesz również wyraźnie poprosić o podpisane znaki za pomocą-fsigned-char
.Na MSVC wartość domyślna jest podpisana, ale można ją zmodyfikować za pomocą
/J
.źródło
C99 N1256 szkic 6.2.5 / 15 „Typy” ma do powiedzenia na temat podpisu typu
char
:oraz w przypisie:
źródło
Według książki The C Programming Language autorstwa Dennisa Ritchiego, która jest de facto standardową książką dla ANSI C, zwykłe znaki ze znakiem lub bez znaku zależą od maszyny, ale znaki drukowalne są zawsze dodatnie.
źródło
Zgodnie ze standardem C podpisanie zwykłego znaku jest „zdefiniowane w implementacji”.
Ogólnie rzecz biorąc, realizatorzy wybrali ten, który był bardziej efektywny do wdrożenia w ich architekturze. W systemach x86 znak jest zwykle podpisany. W systemach z ramieniem jest zwykle niepodpisany (wyjątkiem jest Apple iOS).
źródło
Zgodnie z „The C ++ Programming Language” Bjarne Stroustrup,
char
„implementacja zdefiniowana”. Może to byćsigned char
lub wunsigned char
zależności od implementacji. Możesz sprawdzić, czychar
jest podpisany, czy nie, używającstd::numeric_limits<char>::is_signed
.źródło
Teraz wiemy, że standard pozostawia to do wdrożenia.
Ale jak sprawdzić typ jest
signed
lubunsigned
, na przykładchar
?Napisałem makro, aby to zrobić:
#define IS_UNSIGNED(t) ((t)~1 > 0)
i przetestować go
gcc
,clang
icl
. Ale nie jestem pewien, czy zawsze jest to bezpieczne w innych przypadkach.źródło