İmzasız karakter nedir?


479

C / C ++ 'da ne için unsigned charkullanılır? Normalden farkı charnedir?

Yanıtlar:


548

C ++ 'da üç farklı karakter türü vardır:

  • char
  • signed char
  • unsigned char

Metin için karakter türleri kullanıyorsanız, nitelenmemiş olanı kullanın char:

  • 'a'veya gibi karakter değişmezleri türüdür '0'.
  • C dizelerini oluşturan türdür. "abcde"

Ayrıca bir sayı değeri olarak da çalışır, ancak bu değerin imzalı veya imzasız olarak muamele görüp görmediği belirtilmez. Eşitsizlikler yoluyla karakter karşılaştırmalarına dikkat edin - kendinizi ASCII (0-127) ile sınırlarsanız, hemen hemen güvende olursunuz.

Karakter türlerini sayı olarak kullanıyorsanız , şunu kullanın:

  • signed charsize en az -127 ila 127 aralığı verir. (-128 ila 127 yaygındır)
  • unsigned char, bu da size en az 0 ila 255 aralığı verir.

"En azından", çünkü C ++ standardı yalnızca her sayısal türün kapsaması için gereken minimum değerleri verir. sizeof (char)1 (yani bir bayt) olmalıdır, ancak bir bayt teorik olarak örneğin 32 bit olabilir. sizeofyine de boyutunu1 - sahip olabileceğiniz anlamına gelir sizeof (char) == sizeof (long) == 1.


4
Açıkça söylemek gerekirse, 32 bit karakterlere ve 32 bit tamsayılara sahip olabilir ve sizeof (int)! = Sizeof (char) değerine sahip olabilir misiniz? Standart sizeof (char) == 1 diyor, ama göreceli sizeof (int) gerçek boyut farkına veya aralık farkına dayanıyor mu?
Joseph Garvin

14
+1. Ancak C ++ 'da dört farklı karakter türü vardır, wchar_t bunlardan biridir.
Eric Z

11
c ++ 11'den beri 6 farklı tipiniz vardır: char, işaretli char, unsigned char, wchar_t, char16_t, char32_t.
marcinj

12
@ unheilig sizeofBir işlev değil, bir işleç olduğu için daha sonra boşluk bırakmak yaygındır . Bir değişkenin boyutunu alırken parantezin atlanması daha iyi bir stildir. sizeof *pveya sizeof (int). Bu, bir tür veya değişken için geçerliyse hızlı bir şekilde netleştirir. Aynı şekilde parantez koymak da gereksizdir return. Bu bir işlev değil.
Patrick Schlüter

3
" char: 'a'veya gibi karakter değişmezlerinin türüdür '0'." C ++ 'da doğrudur ancak C değil. C' 'a'de bir int.
chux - Monica'yı

92

Bu, C standardının imzasını tanımlamadığı için uygulamaya bağlıdır char. Platforma bağlı olarak, karakter olabilir signedveya unsignedaçıkça sormak gerekir, böylece signed charya unsigned charda uygulama buna bağlıdır eğer. charDizelerin karakterlerini temsil etmek istiyorsanız kullanın , çünkü bu platformunuzun dizeye koyduğu değerle eşleşir.

Arasındaki fark signed charve unsigned charbeklediğiniz gibi olduğunu. En platformlarında, signed chararasında değişen bir 8-bit ikinin tümleyici numarası olacaktır -128için 127, ve unsigned char(8-bit işaretsiz bir tamsayı olacaktır 0için 255). Standart, chartiplerin 8 bit içermesini GEREKMEZ , sadece bu sizeof(char)dönüşü gerektirdiğini unutmayın 1. Sen bir char bit numaradan alabilirsiniz CHAR_BITiçinde limits.h. Bununla birlikte, bugün bunun dışında bir şey olacağı birkaç platform var 8.

Burada bu sorunun güzel bir özeti var .

Diğerleri bunu gönderdiğimden beri söylediğim gibi, kullanmaktan daha iyidir int8_tve uint8_tgerçekten küçük tam sayıları temsil etmek istiyorsanız.


2
imzalı karakter, minimum -127 ila 127 arasında değişir,
-128'den

3
@ 12431234123412341234123: C standardının -127 ila 127'yi minimum aralık olarak tanımlaması nedeniyle teknik olarak doğrudur. Yine de, ikinin tamamlayıcı aritmetiğini kullanmayan bir platform bulmanıza meydan okuyorum. Hemen hemen her modern platformda, imzalı karakterlerin gerçek aralığı -128 ila 127 olacak.
Todd Gamblin

CHAR_BITstandart tarafından en az 8 bit olmalıdır.
martinkunev

39

Gerçekten çağırıldığını hissediyorum çünkü, sadece C ve C ++ bazı kurallarını belirtmek istiyorum (bu konuda aynıdır). İlk olarak, tüm bitler arasında unsigned chardeğer herhangi bir işaretsiz karakter nesne olmadığını belirlemede katılabilir. İkincisi, unsigned charaçıkça imzasız olarak belirtilir.

Şimdi, -1int türünün değerini dönüştürdüğünüzde ne olacağı hakkında biriyle görüştüm unsigned char. Elde edilen sonucun unsigned chartüm bitlerinin 1'e ayarlandığı fikrini reddetti , çünkü işaret gösterimi konusunda endişeliydi. Ama zorunda değil. Dönüşümün amaçlananı yaptığı hemen bu kuralın dışına çıkar:

Yeni tür imzasızsa, değer, yeni türün aralığına gelinceye kadar, yeni türde temsil edilebilecek maksimum değerden bir kez daha fazla eklenerek veya çıkarılarak dönüştürülür. ( 6.3.1.3p2C99 taslağında)

Bu matematiksel bir açıklama. C ++, aynı kuralı veren modulo hesabı açısından açıklar. Neyse, olan olmayan garantili tamsayı tüm bitleri olmasıdır -1dönüşümden önce biridir. Peki, sonuçta unsigned chartüm CHAR_BITbitlerinin 1'e döndüğünü iddia edebilmek için neye sahibiz ?

  1. Tüm bitler, değerinin belirlenmesine katılır - yani, nesnede hiçbir dolgu biti meydana gelmez.
  2. Sadece bir kez ekleme UCHAR_MAX+1için -1, yani, aralığı içinde bir değere verecektirUCHAR_MAX

Aslında bu yeterli! Bu yüzden unsigned chartüm bitlerine sahip olmak istediğinizde ,

unsigned char c = (unsigned char)-1;

Ayrıca, bir dönüşümün yalnızca yüksek dereceli bitleri kısaltmak olmadığı da anlaşılmaktadır. İkisinin tamamlayıcısı için şanslı olay , bunun sadece bir kısaltma olması, ancak aynı durumun diğer işaret gösterimleri için mutlaka doğru olmamasıdır.


2
Neden sadece kullanmıyorsunuz UCHAR_MAX?
Nicolás

1
Çünkü (unsigned type)-1bir tür deyim. ~0değil.
Patrick Schlüter

1
eğer böyle bir şeyim varsa int x = 1234ve char *y = &x. İkili temsil 1234 DİR 00000000 00000000 00000100 11010010. Makinem biraz endian, bu yüzden tersine çevirir ve 11010010 00000100 00000000 00000000LSB belleğinde saklanır . Şimdi Ana Bölüm. eğer kullanırsam printf("%d" , *p). printfİlk bayt okuyacaktır 11010010çıkıştır -46ama 11010010olan 210bu baskı yok neden bu kadar -46. Ben tam anlamıyla bazı char bir şey yapıyor sanırım gerçekten kafam karıştı ama bilmiyorum.
Suraj Jain

27

Örneğin imzasız karakter kullanımı gibi :

unsigned chargenellikle her renk bileşenine tek bir bayt atayan (her zaman olmasa da) bilgisayar grafiklerinde kullanılır. Her biri 24 (veya 32) bit olarak temsil edilen bir RGB (veya RGBA) rengini görmek yaygındır unsigned char. Yana unsigned chardeğerlerin aralığında [0255] düşmesi, değerleri tipik olarak yorumlanır:

  • 0, belirli bir renk bileşeninin toplam eksikliği anlamına gelir.
  • 255, verilen renk pigmentinin% 100'ü anlamına gelir.

Böylece (255,0,0) -> (% 100 kırmızı,% 0 yeşil,% 0 mavi) olarak RGB kırmızısı elde edersiniz.

Neden a kullanmıyorsunuz signed char? Aritmetik ve bit kaydırma problemli hale gelir. Daha önce açıklandığı gibi, bir signed chararalığı esasen -128 ile değiştirilir. RGB'yi gri tonlamaya dönüştürmek için çok basit ve naif (çoğunlukla kullanılmayan) bir yöntem, üç renk bileşeninin tümünü ortalamaktır, ancak renk bileşenlerinin değerleri negatif olduğunda bu sorunlara yol açar. unsigned charAritmetik kullanılırken kırmızı (255, 0, 0) ortalaması (85, 85, 85) olur . Ancak, değerler signed chars (127, -128, -128) olsaydı, alanımızda (29, 29, 29) olan (-99, -99, -99) ile sonuçlanırdık unsigned char, bu da yanlış .


13

Bir karakteri küçük bir tamsayı olarak kullanmak istiyorsanız, bunu yapmanın en güvenli yolu int8_tve uint8_ttürleridir.


2
İyi bir fikir değil: int8_tve uint8_tisteğe bağlıdır ve bayt boyutunun tam olarak 8 bit olmadığı mimarilerde tanımlanmamıştır. Tersine, signed charve unsigned charher zaman kullanılabilir ve en az 8 bit tutma garantisi vardır. Ortak bir yol olabilir, ancak en güvenli yöntem olmayabilir .
chqrlie

2
Bu bir yorum, soruyu cevaplamıyor.
Lundin

@chqrlie Yani, küçük bir tamsayıyı temsil etmenin en güvenli yolu, eğer hafızadan tasarruf etmek istiyorsanız, signed charve unsigned char? Yoksa bu durumda daha iyi bir "daha güvenli" alternatif tavsiye eder misiniz? Örneğin, "gerçek" tamsayı türlerine bağlı kalmak signed intve unsigned intbunun yerine bir nedenden dolayı?
RobertS

@ RobertS-ReinstateMonica: signed charve unsigned charile uyumlu tüm uygulamalar için taşınabilir ve depolama alanından tasarruf sağlar ancak bazı kod boyutu artışlarına neden olabilir. Bazı durumlarda, küçük değerleri bit alanlarında veya normal tamsayı türlerinin tek bitlerinde depolayarak daha fazla depolama alanı tasarrufu sağlar. Bu sorunun kesin bir cevabı yoktur, bu yaklaşımın uygunluğu eldeki özel duruma bağlıdır. Ve bu cevap zaten soruyu ele almıyor.
chqrlie

10

unsigned charyalnızca pozitif değerler alır .... 0 ila 255 gibi

buna karşılık

signed charhem pozitif hem de negatif değerleri alır .... -128 ila +127 gibi


9

charve unsigned chartüm platformlarda 8 bit tür olduğu garanti edilmez; bunların 8 bit veya daha büyük olduğu garanti edilir. Bazı platformlarda 9 bit, 32 bit veya 64 bit bayt bulunur . Ancak, bugün en yaygın platformlarda (Windows, Mac, Linux x86 vb.) 8 bit bayt vardır.


8

signed char-128 ila 127 aralığındadır; unsigned char0 ila 255 aralığındadır.

char derleyiciye bağlı olarak imzalı karakter veya imzasız karaktere eşdeğer olacaktır, ancak farklı bir türdür.

C tarzı dizeler kullanıyorsanız, kullanın char. Aritmetik (oldukça nadir) için karakter kullanmanız gerekiyorsa, taşınabilirlik için imzalı veya imzasız olarak açıkça belirtin.


8

An unsigned char, işaretsiz bir bayt değeridir (0 ila 255). charBir "karakter" olarak düşünüyor olabilirsiniz, ama bu gerçekten sayısal bir değerdir. Normal charimzalanmıştır, bu nedenle 128 değeriniz vardır ve bu değerler ASCII kodlamasını kullanan karakterlerle eşleşir. Ancak her iki durumda da, bellekte sakladığınız şey bir bayt değeridir.


7

Doğrudan değerler açısından, değerlerin arasında olduğu bilindiğinde CHAR_MINve CHAR_MAXimzasız bir karakter pozitif uçtaki aralığı iki katına çıkarırken normal bir karakter kullanılır . Örneğin CHAR_BIT, 8 ise , normal aralığın charyalnızca [0, 127] olduğu (çünkü imzalanabileceği veya imzalanabileceği) unsigned char[0, 255] ve signed char[-127, 127] olacağı garanti edilir .

Ne için kullanıldıkları açısından, standartlar POD (düz eski veriler) nesnelerinin doğrudan işaretsiz karakter dizisine dönüştürülmesine izin verir. Bu, nesnenin temsilini ve bit desenlerini incelemenizi sağlar. Char veya imzalı char için aynı güvenli tip çiftçilik garantisi yoktur.


Aslında, en sık [-128, 128] olacaktır.
RastaJedi

Standartları sadece resmi bir şekilde cisim tanımlayan dizinin arasında unsigned chardeğil, bir dizi spesifik olarak, herhangi bir "dönüşüm", sadece resmi ile tanımlanır kopyalama bir gerçek nesneden, ilan dizi arasında unsigned charve daha sonra, sözkonusu kontrol. OR'nin böyle bir dizi olarak doğrudan yeniden yorumlanıp yorumlanamayacağı açık değildir, işaretçi aritmetiği için ödeneklerle, yani ==bu kullanımda "dizi" "dizisi" olup olmadığı açık değildir . Bunun açıklığa kavuşturulması umuduyla # 1701 numaralı bir Temel Sorun var. Neyse ki, bu belirsizlik beni son zamanlarda gerçekten rahatsız ediyor.
underscore_d

1
@RastaJedi Hayır, olmayacak. Yapamaz. -128 ... + 128 aralığında 8 bit ile temsil edilmesi fiziksel olarak imkansızdır. Bu genişlik yalnızca 2 ^ 8 == 256 ayrık değeri destekler, ancak 0 = 257 için -128 ... + 128 = 2 * 128 + 1'i destekler. İşaret büyüklüğü gösterimi -127 ... + 127'ye izin verir, ancak 2 (iki kutuplu) sıfır. İkinin tamamlayıcı gösterimi tek bir sıfır tutar, ancak negatif tarafta bir değer daha oluşturarak aralığı oluşturur; -128 ... + 127'ye izin verir. (Ve daha büyük bit genişliklerinde her ikisi için de geçerlidir.)
underscore_d

2. yorumum, OR'in 1'ine bir işaretçi alabileceğimizi ve oradan her baytı okumak için kullanmaya devam edebileceğimizi varsaymak mantıklıdır ... ancak AFAICT, özellikle izin verildiği olarak tanımlanmadı, bir bilmeceye benzer, Standart diğer birçok pasajlardan (ve birçok yönden, sadece varlığı ) 'muhtemelen' OK çıkarım yaptı . Hangi ideal değil. Belki de eninde sonunda ifadeler gelişecektir. Bahsettiğim ancak bağlantı kurmak için yeterli alan bulunmayan CWG sorunu - open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1701unsigned char++ptrmemcpy
underscore_d

@underscore_d üzgünüm, bu bir yazım hatasıydı. [-128, 127] yazmak istediğim şey: p. Evet, işaret / büyüklükte çift sıfırları ('pozitif' ve 'negatif' sıfır) biliyorum. Yorgun olmalıydım: s.
RastaJedi

5

unsigned chartüm bitlerin kalbidir. ALL platformu için neredeyse ALL derleyicisinde, an unsigned charsadece küçük bir tamsayı veya bir bit paketi olarak işlenebilen bir bayt ve imzasız (genellikle) 8 bitlik bir tamsayıdır.

Bağımlılıkta, başka birinin söylediği gibi, standart bir karakterin işaretini tanımlamaz. Böylece 3 ayrı olması chartürleri: char, signed char, unsigned char.


1
Bit hile, aka bit twiddling veya bit hack gerçekten bağımlılık neden olduğu bilinmektedir ;-)
chqrlie

3
Problemlere sebep olan 0'lar. Twiddling bağımlılığı önlemek için, göze çarpan bit uzak dur.
DragonLord

5

Belirli uzunluk ve signedness çeşitli kullanmak gibi, muhtemelen daha iyi durumda olan iseniz uint8_t, int8_t, uint16_tvb yaptıkları çünkü onlar dediklerimi.


4

Bazı bulundu googling bu kişiler bu hakkında bir tartışma vardı nerede.

İmzasız bir karakter temelde tek bir bayttır. Bu nedenle, bir bayt veriye ihtiyacınız varsa bunu kullanırsınız (örneğin, genellikle Windows API'da yapıldığı gibi bir işleve geçirilecek bayrakları açmak ve kapatmak için kullanmak isteyebilirsiniz).


4

İmzasız bir karakter, normal bir karakterin işareti için ayrılan biti başka bir sayı olarak kullanır. Bu, aralığı [-128 - 127] yerine [0 - 255] olarak değiştirir.

Bir işaret istemediğinizde genellikle işaretsiz karakterler kullanılır. Bu, bir karakter ile sayı olarak kullanmak yerine bayt olarak uğraşırken, bitleri değiştirmek (kaydırma işareti uzatır) ve diğer şeyleri yaparken bir fark yaratacaktır.


4

unsigned charyalnızca pozitif değerleri alır: 0 - 255 arası signed charpozitif ve negatif değerleri alır: -128 ila +127.


3

alıntı frome "c programlama laugage" kitap:

Niteleyici signedveya unsignedkömür ya da herhangi bir tam sayı tatbik edilebilir. imzasız sayılar her zaman pozitif veya sıfırdır ve aritmetik modulo 2 ^ n yasalarına uyun; burada n, türdeki bit sayısıdır. Örneğin, eğer karakter 8 bit ise, imzasız karakter değişkenleri 0 ile 255 arasında değerlere sahipken, imzalı karakterlerin değeri -128 ile 127 arasındadır (iki tamamlayıcı makinede.) Düz karakterlerin imzalı veya imzasız olup olmadığı makinedir. bağımsız, ancak yazdırılabilir karakterler her zaman pozitiftir.


2

signed charve unsigned charher ikisi de 1baytı temsil eder, ancak farklı aralıkları vardır.

   Type        |      range
-------------------------------
signed char    |  -128 to +127
unsigned char  |     0 to 255

Gelen signed chardüşündüğümüz takdirde char letter = 'A', 'A' içinde 65 ikili temsil olduğu ASCII/Unicode65 saklanabilir ise, -65 da saklanabilir. ASCII/UnicodeNegatif değerler için endişelenmenize gerek olmadığı için orada negatif ikili değerler yoktur.

Misal

#include <stdio.h>

int main()
{
    signed char char1 = 255;
    signed char char2 = -128;
    unsigned char char3 = 255;
    unsigned char char4 = -128;

    printf("Signed char(255) : %d\n",char1);
    printf("Unsigned char(255) : %d\n",char3);

    printf("\nSigned char(-128) : %d\n",char2);
    printf("Unsigned char(-128) : %d\n",char4);

    return 0;
}

Çıktı -:

Signed char(255) : -1
Unsigned char(255) : 255

Signed char(-128) : -128
Unsigned char(-128) : 128
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.