W C / C ++ do czego unsigned char
służy an ? Czym różni się od zwykłego char
?
479
W C ++ istnieją trzy różne typy znaków:
char
signed char
unsigned char
Jeśli używasz typów znaków dla tekstu , użyj niekwalifikowanego char
:
'a'
lub '0'
."abcde"
Działa również jako wartość liczbowa, ale nie jest określone, czy ta wartość jest traktowana jako podpisana czy niepodpisana. Uważaj na porównania postaci przez nierówności - chociaż ograniczając się do ASCII (0-127), jesteś prawie bezpieczny.
Jeśli używasz typów znaków jako liczb , użyj:
signed char
, co daje co najmniej zakres od -127 do 127. (Od -128 do 127 jest powszechne)unsigned char
, co daje co najmniej zakres od 0 do 255.„Przynajmniej”, ponieważ standard C ++ podaje tylko minimalny zakres wartości, który musi obejmować każdy typ liczbowy. sizeof (char)
wymagana jest wartość 1 (tj. jeden bajt), ale bajt teoretycznie może wynosić na przykład 32 bity. sizeof
nadal będzie zgłosić swoją wielkość, jak1
- co oznacza, że mogłyby mieć sizeof (char) == sizeof (long) == 1
.
sizeof
ponieważ nie jest to funkcja, ale operator. Jeszcze lepszym stylem jest pominięcie nawiasu przy przyjmowaniu wielkości zmiennej.sizeof *p
lubsizeof (int)
. Dzięki temu szybko staje się jasne, czy ma zastosowanie do typu lub zmiennej. Podobnie zbędne jest umieszczanie nawiasów poreturn
. To nie jest funkcja.char
: to rodzaj literałów znakowych takich jak'a'
lub'0'
.” jest prawdziwe w C ++, ale nie w C. W C'a'
jestint
.Jest to zależne od implementacji, ponieważ standard C NIE definiuje podpisu
char
. W zależności od platformy char może byćsigned
lubunsigned
, więc musisz jawnie o to poprosićsigned char
lub odunsigned char
tego zależy twoja implementacja. Po prostu użyjchar
jeśli zamierzasz reprezentować znaki z ciągów, ponieważ będą one pasować do tego, co twoja platforma umieszcza w ciągu.Różnica między
signed char
iunsigned char
jest taka, jak można się spodziewać. Na większości platformsigned char
będzie 8-bitową liczbą uzupełnień do dwóch, od-128
do127
, iunsigned char
będzie 8-bitową liczbą całkowitą bez znaku (0
do255
). Uwaga standard nie wymaga, abychar
typy miały 8 bitów, tylko tensizeof(char)
zwrot1
. Możesz dostać się do liczby bitów w znaku zCHAR_BIT
inlimits.h
. Istnieje jednak niewiele, jeśli w ogóle, platform, na których będzie to coś innego niż8
.Ładne streszczenie tego problemu znajduje się tutaj .
Jak wspomnieli inni, odkąd to opublikowałem, lepiej jest używać
int8_t
iuint8_t
jeśli naprawdę chcesz reprezentować małe liczby całkowite.źródło
CHAR_BIT
zgodnie z normą wymagane jest co najmniej 8 bitów.Ponieważ czuję, że jest to naprawdę potrzebne, chcę tylko podać niektóre zasady C i C ++ (są one pod tym względem takie same). Po pierwsze, wszystkie bity od
unsigned char
udziału w ustalaniu wartości, jeśli jakiekolwiek unsigned char obiektu. Po drugie,unsigned char
jest wyraźnie określony jako niepodpisany.Teraz rozmawiałem z kimś o tym, co się dzieje, kiedy konwertujesz wartość
-1
typu int naunsigned char
. Odrzucił ideę, że wynikoweunsigned char
ma wszystkie bity ustawione na 1, ponieważ martwił się reprezentacją znaków. Ale nie musi. Bezpośrednio z tej reguły wynika, że konwersja robi to, co jest zamierzone:To jest opis matematyczny. C ++ opisuje to w kategoriach rachunku modułowego, który daje tę samą regułę. W każdym razie, co nie gwarantuje, że wszystkie bity w całkowitej
-1
są jednym przed konwersją. Co więc mamy, abyśmy mogli twierdzić, że wynikowyunsigned char
ma wszystkieCHAR_BIT
bity zmienione na 1?UCHAR_MAX+1
na-1
przyniesie wartość w zakresie, a mianowicieUCHAR_MAX
Właściwie to wystarczy! Tak więc, kiedy tylko chcesz mieć
unsigned char
wszystkie swoje bity, robisz toWynika z tego również, że konwersja to nie tylko obcinanie bitów wyższego rzędu. Szczęśliwym wydarzeniem dla uzupełnienia dwóch jest to, że jest to tylko obcięcie, ale niekoniecznie tak samo jest w przypadku innych reprezentacji znaków.
źródło
UCHAR_MAX
?(unsigned type)-1
to jakiś idiom.~0
nie jest.int x = 1234
ichar *y = &x
. Binarna reprezentacja1234
jest00000000 00000000 00000100 11010010
. Moja maszyna jest małym endianem, więc odwraca ją i zapisuje w pamięci11010010 00000100 00000000 00000000
LSB na pierwszym miejscu. Teraz główna część. jeśli użyjęprintf("%d" , *p)
.printf
odczyta pierwszy bajt11010010
tylko wyjście-46
, ale11010010
jest210
tak dlatego to wydrukować-46
. Naprawdę jestem zdezorientowany. Wydaje mi się, że jakiś znak do promocji liczb całkowitych robi coś, ale nie wiem.Na przykład zastosowania niepodpisanego znaku :
unsigned char
jest często stosowany w grafice komputerowej, która bardzo często (choć nie zawsze) przypisuje jeden bajt do każdego komponentu koloru. Często zdarza się, że kolor RGB (lub RGBA) reprezentowany jest przez 24 (lub 32) bity każdyunsigned char
. Ponieważunsigned char
wartości mieszczą się w zakresie [0,255], są one zazwyczaj interpretowane jako:Tak więc otrzymałeś czerwony RGB jako (255,0,0) -> (100% czerwony, 0% zielony, 0% niebieski).
Dlaczego nie użyć
signed char
? Arytmetyka i zmiana bitów staje się problematyczna. Jak już wyjaśniono,signed char
zakres a jest zasadniczo przesunięty o -128. Bardzo prostą i naiwną (najczęściej nieużywaną) metodą konwersji RGB na skalę szarości jest uśrednienie wszystkich trzech składników koloru, ale napotyka to problemy, gdy wartości składników koloru są ujemne. Średnie czerwone (255, 0, 0) to (85, 85, 85) przy zastosowaniuunsigned char
arytmetyki. Jednak jeśli wartości byłybysigned char
s (127, -128, -128), otrzymalibyśmy (-99, -99, -99), co byłoby (29, 29, 29) w naszejunsigned char
przestrzeni, co jest niepoprawne .źródło
Jeśli chcesz użyć znaku jako małej liczby całkowitej, najbezpieczniejszym sposobem na to jest użycie typów
int8_t
iuint8_t
.źródło
int8_t
iuint8_t
są opcjonalne i nie zdefiniowano na architekturach gdzie wielkość bajt nie jest dokładnie 8 bitów. I odwrotnie,signed char
iunsigned char
zawsze są dostępne i gwarantują, że mieszczą co najmniej 8 bitów. Może to być powszechny sposób, ale nie najbezpieczniejszy .signed char
iunsigned char
? A może poleciłbyś lepszą „bezpieczniejszą” alternatywę w tym konkretnym przypadku? Na przykład trzymać się „prawdziwych” liczb całkowitychsigned int
iunsigned int
zamiast tego z jakiegoś powodu?signed char
iunsigned char
jest przenośne dla wszystkich zgodnych implementacji i pozwoli zaoszczędzić miejsce, ale może spowodować pewne zwiększenie rozmiaru kodu. W niektórych przypadkach można zaoszczędzić więcej miejsca, przechowując małe wartości w polach bitowych lub pojedynczych bitach zwykłych liczb całkowitych. Nie ma absolutnej odpowiedzi na to pytanie, znaczenie tego podejścia zależy od konkretnego rozpatrywanego przypadku. Ta odpowiedź i tak nie odnosi się do pytania.unsigned char
przyjmuje tylko wartości dodatnie .... jak 0 do 255natomiast
signed char
przyjmuje zarówno dodatnie, jak i ujemne wartości .... jak -128 do +127źródło
char
iunsigned char
nie ma gwarancji, że będą to typy 8-bitowe na wszystkich platformach - są gwarantowane, że są 8-bitowe lub większe. Niektóre platformy mają 9-bitowe, 32-bitowe lub 64-bitowe bajty . Jednak najpopularniejsze obecnie platformy (Windows, Mac, Linux x86 itp.) Mają 8-bitowe bajty.źródło
signed char
ma zakres od -128 do 127;unsigned char
ma zakres od 0 do 255.char
będzie równoważny znakowi podpisanemu lub znakowi niepodpisanemu, w zależności od kompilatora, ale jest odrębnym typem.Jeśli używasz ciągów w stylu C, po prostu użyj
char
. Jeśli musisz używać znaków do obliczeń arytmetycznych (dość rzadko), podaj wyraźnie podpisane lub niepodpisane w celu przenoszenia.źródło
An
unsigned char
jest bajtem bez znaku (od 0 do 255). Być może myślisz ochar
byciu „postacią”, ale tak naprawdę jest to wartość liczbowa. Normalnychar
jest podpisany, więc masz 128 wartości, które są mapowane na znaki przy użyciu kodowania ASCII. Ale w obu przypadkach to, co przechowujesz w pamięci, to wartość bajtowa.źródło
Jeśli chodzi o wartości bezpośrednie, zwykły znak jest używany, gdy wiadomo, że wartości są pomiędzy,
CHAR_MIN
aCHAR_MAX
gdy znak bez znaku zapewnia podwójny zakres na dodatnim końcu. Na przykład, jeśliCHAR_BIT
jest to 8, zakres wartości regularnychchar
jest gwarantowany tylko na [0, 127] (ponieważ może być podpisany lub niepodpisany), podczas gdyunsigned char
będzie wynosił [0, 255] isigned char
będzie wynosił [-127, 127].Pod względem tego, do czego jest używany, standardy pozwalają bezpośrednio konwertować obiekty POD (zwykłe stare dane) na tablicę znaków bez znaku. Umożliwia to sprawdzenie reprezentacji i wzorów bitowych obiektu. Ta sama gwarancja bezpiecznego znakowania czcionek nie istnieje dla znaków ani znaków podpisanych.
źródło
unsigned char
, a nie tablicy Specyficznie, każdy „konwersja” jest zdefiniowany tylko formalnie przez skopiowanie od obiektu do rzeczywistego, stwierdził tablicę zunsigned char
i następnie kontroli ostatnich. Nie jest jasne, czy OR można bezpośrednio zinterpretować jako taką tablicę, z uwzględnieniem dopuszczalnej arytmetyki wskaźnika, tj. Czy==
„tablica” „tablica” w tym zastosowaniu. Mamy nadzieję, że uda się to wyjaśnić. Na szczęście, ponieważ ta dwuznaczność naprawdę mnie ostatnio denerwuje.unsigned char
OR, a następnie kontynuować korzystanie++ptr
z tego miejsca, aby odczytać każdy jego bajt ... ale AFAICT, nie jest specjalnie zdefiniowany jako dozwolony, więc jesteśmy pozostawiono, aby wywnioskować, że „prawdopodobnie jest OK” z wielu innych fragmentów (i na wiele sposobów, samego istnieniamemcpy
) w standardzie, podobnie jak układanka. Co nie jest idealne. Cóż, być może brzmienie ostatecznie się poprawi. Oto problem CWG, o którym wspomniałem, ale brakowało miejsca na link - open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1701unsigned char
jest sercem wszystkich sztuczek. W prawie WSZYSTKIM kompilatorze dla WSZYSTKICH platform jestunsigned char
to po prostu bajt i liczba całkowita bez znaku (zwykle) 8 bitów, które mogą być traktowane jako mała liczba całkowita lub paczka bitów.Nałogowo, jak powiedział ktoś inny, standard nie definiuje znaku znaku. tak masz 3 różne
char
typy:char
,signed char
,unsigned char
.źródło
Jeśli podoba Ci się stosując różne typy i długości określonej signedness, jesteś prawdopodobnie lepiej z
uint8_t
,int8_t
,uint16_t
itd po prostu dlatego, że robią dokładnie to, co mówią.źródło
Niektórzy google znaleźli to , gdzie ludzie rozmawiali o tym.
Znak bez znaku jest w zasadzie pojedynczym bajtem. Tak więc użyłbyś tego, jeśli potrzebujesz jednego bajtu danych (na przykład, może chcesz go użyć do włączania i wyłączania flag, aby były przekazywane do funkcji, jak to często robi się w interfejsie API Windows).
źródło
Znak bez znaku używa bitu zarezerwowanego dla znaku zwykłego znaku jako innej liczby. Zmienia to zakres na [0–255] w przeciwieństwie do [-128–127].
Zasadniczo znaki bez znaku są używane, gdy nie chcesz znaku. Będzie to miało znaczenie podczas robienia rzeczy, takich jak przesuwanie bitów (shift wydłuża znak) i innych rzeczy, gdy ma się do czynienia z char jako bajtem, a nie z użyciem go jako liczby.
źródło
unsigned char
przyjmuje tylko wartości dodatnie: od 0 do 255, asigned char
przyjmuje wartości dodatnie i ujemne: od -128 do +127.źródło
cytowany z książki „la cage programowania”:
Kwalifikator
signed
lubunsigned
może być zastosowany do znaku lub dowolnej liczby całkowitej. liczby bez znaku są zawsze dodatnie lub zerowe i są zgodne z prawami arytmetycznego modułu 2 ^ n, gdzie n jest liczbą bitów w typie. Na przykład, jeśli znaki to 8 bitów, zmienne znakowane bez znaku mają wartości od 0 do 255, podczas gdy znaki podpisane mają wartości od -128 do 127 (w maszynie dopełniającej dwa.) To, czy zwykłe znaki są podpisane czy niepodpisane, jest maszyną -zależne, ale znaki do wydruku są zawsze dodatnie.źródło
signed char
iunsigned char
oba reprezentują 1 bajt, ale mają różne zakresy.W
signed char
jeśli weźmiemy pod uwagęchar letter = 'A'
, „A” ma reprezentować binarnie z 65 wASCII/Unicode
, przypadku 65 mogą być przechowywane, -65 może być również przechowywane. Nie ma tam ujemnych wartości binarnych, więcASCII/Unicode
nie musisz się martwić o wartości ujemne.Przykład
Wynik -:
źródło