什么是未签名的字符?


479

在C / C ++中,an的作用unsigned char是什么?与常规有什么不同char

Answers:


548

在C ++中,存在三种不同的字符类型:

  • char
  • signed char
  • unsigned char

如果将字符类型用于文本,请使用不限定的字符char

  • 它是字符文字如'a'或的类型'0'
  • 它是组成C字符串的类型,例如 "abcde"

它也可以作为数字值计算,但是不确定该值是带符号的还是无符号的。注意通过不等号进行字符比较-尽管如果将自己限制为ASCII(0-127),则几乎是安全的。

如果将字符类型用作数字,请使用:

  • signed char,该范围至少为-127至127。(-128至127是常见的)
  • unsigned char,该值至少为0到255。

“至少”,因为C ++标准仅给出了每种数字类型都必须覆盖的最小范围的值。sizeof (char)要求1为1(即一个字节),但是理论上一个字节可以是例如32位。sizeof仍将其大小报告为1 -表示您可以拥有sizeof (char) == sizeof (long) == 1


4
需要明确的是,您可以使用32位字符和32位整数,并具有sizeof(int)!= sizeof(char)吗?我知道标准说sizeof(char)== 1,但是相对sizeof(int)是基于实际大小差异还是范围差异?

14
+1。但是C ++中有四种不同的字符类型,wchar_t是其中之一。
Eric Z

11
从c ++ 11开始,您有6种不同的类型:char,有符号的char,无符号的char,wchar_t,char16_t,char32_t。
marcinj 2014年

12
@unheilig通常在其后放置一个空格,sizeof因为它不是函数,而是运算符。取变量的大小时,省略括号是一种更好的样式。sizeof *psizeof (int)。这样可以快速弄清楚是否适用于类型或变量。同样,在后面加上括号也是多余的return。这不是功能。
PatrickSchlüter2014年

3
char:这是字符文字的类型,例如'a''0'。” 在C ++中是正确的,但在C中不是。在C中,'a'int
chux-恢复莫妮卡

92

这取决于实现,因为C标准没有定义的符号char。根据平台的不同,char可能是signedunsigned,因此您需要明确要求signed charunsigned char您的实现是否依赖于它。仅char在您打算表示字符串中的字符时使用,因为这将与您的平台在字符串中放置的字符匹配。

signed char和之间的区别unsigned char是您所期望的。在大多数平台上,signed char将是8位二进制补码,范围是从-128127,并且unsigned char将是8位无符号整数(0to 255)。注意,该标准不要求char类型具有8位,仅要求sizeof(char)return 1。您可以在位的数量得到一个字符用CHAR_BITlimits.h。如今,几乎没有任何平台会提供8,而不是。

有这个问题的一个很好的总结在这里

正如我自发布此文章以来其他人提到的那样int8_tuint8_t如果您真的想表示小整数,最好使用。


2
签名的字符的最小范围是-127到127,而不是-128到127
12431234123412341234123'1

3
@ 12431234123412341234123:从技术上讲是正确的,因为C标准将-127到127定义为最小范围。但是,我挑战您找到一个不使用二进制补码算法的平台。在几乎每一个现代化的平台,签署字符的实际范围是-128到127
托德布林

CHAR_BIT标准要求至少为8位。
martinkunev

39

因为我觉得确实需要这样做,所以我只想陈述一些C和C ++的规则(在这方面它们是相同的)。首先,所有unsigned char参与的都参与确定该值(如果有任何未签名的char对象)。第二,unsigned char明确声明未签名。

现在,我与某人讨论了将-1int类型的值转换为时会发生什么unsigned char。他拒绝将结果的unsigned char所有位都设置为1 的想法,因为他担心符号的表示。但他不必。遵循此规则,转换立即达到了预期的目的:

如果新类型是无符号的,则通过重复添加或减去比新类型中可以表示的最大值多一个值来转换该值,直到该值在新类型的范围内为止。(6.3.1.3p2在C99草案中)

那是数学上的描述。C ++用模演算来描述它,这产生了相同的规则。无论如何,不能保证整数-1中的所有位在转换前都是1。那么,我们有什么,可以断言结果的unsigned char所有CHAR_BIT位都变为1?

  1. 所有位都参与确定其值-也就是说,对象中没有填充位。
  2. 只添加一次UCHAR_MAX+1,以-1将产生在范围内的值,即UCHAR_MAX

够了,实际上!因此,每当您想拥有一个unsigned char全部的位时,您就会

unsigned char c = (unsigned char)-1;

随之而来的是,转换只是截断高阶位。二进制补码的幸运事件是它只是一个截断,但对于其他符号表示形式并不一定是正确的。


2
为什么不只是使用UCHAR_MAX
–Nicolás

1
因为(unsigned type)-1是某种成语。~0不是。
PatrickSchlüter2014年

1
如果我有这样的东西int x = 1234char *y = &x1234 is的二进制表示形式00000000 00000000 00000100 11010010。我的机器是小字节序的,因此它将其反转并存储在内存中11010010 00000100 00000000 00000000LSB优先。现在主要部分。如果我使用printf("%d" , *p)printf将读取第一个字节11010010只输出-46,但11010010就是210为何还打印-46。我真的很困惑,我想一些将char转换为整数的促销正在做某事,但我不知道。
Suraj Jain

27

例如unsigned char的用法:

unsigned char通常在计算机图形学中使用,它经常(尽管并非总是)为每个颜色分量分配一个字节。通常会看到以24(或32)位表示的RGB(或RGBA)颜色,每个为unsigned char。由于unsigned char值在[0,255]范围内,因此通常将这些值解释为:

  • 0表示完全缺少给定的颜色分量。
  • 255表示给定颜色颜料的100%。

因此,最终将得到RGB红色为(255,0,0)->(100%红色,0%绿色,0%蓝色)。

为什么不使用signed char?算术和位移会成为问题。正如已经说明的,signed char的范围实际上偏移了-128。将RGB转换为灰度的一种非常简单且幼稚的方法(几乎未使用)是对所有三个颜色分量求平均值,但是当颜色分量的值为负时,就会遇到问题。使用unsigned char算术运算时,红色(255,0,0)平均为(85,85,85)。但是,如果值是signed chars(127,-128,-128),我们最终将得到(-99,-99,-99),在我们的unsigned char空间中将是(29,29,29),这是不正确的。


13

如果要将字符用作小整数,最安全的方法是使用int8_tand uint8_t类型。


2
这不是一个好主意:int8_t并且uint8_t是可选的,并且未在字节大小不完全为8​​位的体系结构上定义。相反,signed char并且unsigned char始终可用,并保证至少持有8位。这可能是常见的方法,但不是最安全的方法
chqrlie 2015年

2
这是一条评论,无法回答问题。
伦丁

@chqrlie所以,您的意思是,如果要节省内存,表示小整数的最安全方法就是保留signed charunsigned char?还是在特定情况下您会推荐一个更好的“更安全”的选择?例如,坚持使用“实数”整数类型signed intunsigned int而出于某种原因呢?
RobertS支持Monica Cellio

@ RobertS-ReinstateMonica:使用signed charunsigned char可移植到所有符合要求的实现中,将节省存储空间,但可能会导致代码大小增加。在某些情况下,通过将较小的值存储在规则整数类型的位字段或单个位中,可以节省更多的存储空间。这个问题没有绝对的答案,这种方法的针对性取决于具体情况。而且这个答案也不能解决这个问题。
chqrlie

10

unsigned char只接受正值...。例如0255

在哪里

signed char同时接受正值和负值...如-128+127


9

charunsigned char不能保证在所有平台上均为8位类型,而是保证为8位或更大。某些平台具有9位,32位或64位byte。但是,当今最常见的平台(Windows,Mac,Linux x86等)具有8位字节。


8

signed char范围为-128至127;unsigned char范围为0到255。

char 根据编译器的不同,将等效于有符号字符或无符号字符,但它是不同的类型。

如果您使用的是C风格的字符串,请使用char。如果您需要使用char进行算术运算(很少见),请为可移植性明确指定有符号或无符号。


8

An unsigned char是无符号字节值(0到255)。您可能会想到char成为“字符”,但这实际上是一个数字值。常规char符号是带符号的,因此您有128个值,并且这些值使用ASCII编码映射到字符。但是无论哪种情况,您存储在内存中的都是一个字节值。


7

就直接值而言,当已知值介于CHAR_MIN或之间时使用常规字符CHAR_MAX,而无符号字符在正数端提供两倍的范围。例如,如果CHAR_BIT为8,则常规的范围char仅保证为[0,127](因为它可以签名或无符号),而unsigned char将为[0,255],并且signed char为[-127,127]。

就其用途而言,标准允许将POD(普通旧数据)的对象直接转换为无符号字符数组。这使您可以检查对象的表示形式和位模式。对于char或signed char,不存在相同的安全类型修剪保证。


实际上,通常是[-128,128]。
RastaJedi '16

这些标准仅正式定义的对象表示为序列unsigned char,而不是一个阵列具体地,&任何“转化率”是只由正式定义复制从对象到一个真实的,宣告阵列unsigned char&然后检查后者。尚不清楚OR是否可以直接重新解释为这样的数组,是否需要使用指针算术,即==在此用法中是否使用“序列” “数组”。有一个核心问题#1701已公开,希望对此予以澄清。值得庆幸的是,这种模糊性最近确实困扰了我。
underscore_d

1
@RastaJedi不,不会。不可以 -128 ... + 128的范围实际上不可能用8位表示。该宽度仅支持2 ^ 8 == 256个离散值,但-128 ... + 128 = 2 * 128 +1(0 = 257)。符号幅度表示允许-127 ... + 127,但具有2(双极)零。二进制补码表示保持单个零,但通过在负数侧具有一个更多的值来构成范围;它允许-128 ... + 127。(对于较大的位宽,都这样,以此类推。)
underscore_d

在我的第二条评论中,假设我们可以将一个指针指向unsigned charOR 的第一个,然后++ptr从那里开始使用它来读取它的每个字节是合理的……但是AFAICT,没有明确定义为允许,所以我们可以从标准中的许多其他段落(以及在许多方面,仅仅是的存在memcpy)推断出它“可能还可以”,类似于拼图游戏。这是不理想的。好吧,也许措辞最终会有所改善。这是我提到的CWG问题,但缺乏链接空间-open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1701
underscore_d

@underscore_d对不起,那是一个错字。[-128,127]是我要输入:p的意思。是的,我知道带符号/大小的双零(“正”和“负”零)。我一定很累:p。
RastaJedi '16

5

unsigned char是所有骗术的心脏。在几乎所有平台的ALL编译器中,unsigned chara只是一个字节和(通常)8位的无符号整数,可以将其视为小整数或一包位。

正如其他人所说,在成瘾中,标准没有定义字符的符号。所以你有3种不同的char类型:charsigned charunsigned char


1
比特骗术,aka twiddling或bit hacking确实会引起上瘾;-)
chqrlie

3
导致问题的原因是0。为了避免上瘾引起纠缠,请远离顽皮的位子。
DragonLord

5

如果你喜欢使用各种特定的长度和符号性的,你可能有更好uint8_tint8_tuint16_t,等他们说什么,只是因为他们做的。


4

一些谷歌搜索发现了这一点,人们对此进行了讨论。

无符号字符基本上是一个字节。因此,如果需要一个字节的数据,则可以使用它(例如,可能要使用它来设置标志的开和关,以将其传递给函数,就像Windows API中经常执行的那样)。


4

无符号字符使用保留给常规字符符号的位作为另一个数字。这会将范围更改为[0-255],而不是[-128-127]。

通常,当您不想要符号时使用未签名的字符。这在执行诸如移位位(shift扩展符号)之类的操作以及将char作为字节而不是将其用作数字的其他操作时会有所不同。


4

unsigned char仅采用正值:0至255,而 signed char采用正值和负值:-128至+127。


3

引用《 c编程专家》一书:

限定符signedunsigned可以应用于char或任何整数。无符号数始终为正或零,并遵守2 ^ n取模的数学定律,其中n是类型中的位数。因此,例如,如果char是8位,则无符号char变量的值在0到255之间,而有符号char的值在-128到127之间(在二进制补码机中。)普通字符是有符号还是无符号是机器依赖,但可打印字符始终为正。


2

signed charunsigned char都代表1字节,但是它们具有不同的范围。

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

signed char如果我们考虑char letter = 'A',“A”是代表在65二进制ASCII/Unicode,如果65可以存储,还-65可以存储。那里没有负的二进制值,ASCII/Unicode无需担心负值。

#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;
}

输出-

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

Signed char(-128) : -128
Unsigned char(-128) : 128
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.