在 C++ 中,存在三种不同的字符类型:
字符
签名字符
无符号的字符
如果您对 text 使用字符类型,请使用不合格的 char
:
它是字符文字的类型,例如“a”或“0”(仅在 C++ 中,在 C 中它们的类型是 int)
它是构成诸如“abcde”之类的 C 字符串的类型
它也可以作为一个数字值,但未指定该值是被视为有符号还是无符号。当心通过不等式进行字符比较 - 尽管如果您将自己限制在 ASCII (0-127) 范围内,那么您几乎是安全的。
如果您将字符类型用作数字,请使用:
带符号的字符,它至少为您提供 -127 到 127 的范围。 (-128 到 127 很常见)
unsigned char,它至少为您提供 0 到 255 的范围。
“至少”,因为 C++ 标准只给出了每种数字类型需要覆盖的最小值范围。 sizeof (char)
必须为 1(即一个字节),但理论上一个字节可以是例如 32 位。 sizeof
仍会将其大小报告为 1
- 这意味着您可以拥有 sizeof (char) == sizeof (long) == 1
。
这取决于实现,因为 C 标准没有定义 char
的符号性。根据平台,char 可能是 signed
或 unsigned
,因此如果您的实现依赖于它,您需要明确要求 signed char
或 unsigned char
。如果您打算表示字符串中的字符,只需使用 char
,因为这将匹配您的平台在字符串中放置的内容。
signed char
和 unsigned char
之间的区别正如您所料。在大多数平台上,signed char
将是一个 8 位二进制补码,范围从 -128
到 127
,而 unsigned char
将是一个 8 位无符号整数(0
到 255
)。请注意,该标准不要求 char
类型具有 8 位,仅要求 sizeof(char)
返回 1
。您可以使用 limits.h
中的 CHAR_BIT
获取 char 中的位数。但是,今天很少有平台会出现 8
之外的内容。
这个问题有一个很好的总结here。
正如其他人在我发布此内容后所提到的那样,如果您真的想表示小整数,最好使用 int8_t
和 uint8_t
。
CHAR_BIT
至少为 8 位。
因为我觉得真的很需要,所以我只想说一下C和C++的一些规则(在这方面是一样的)。首先,如果有任何 unsigned char 对象,unsigned char
的所有位 都参与确定值。其次,unsigned char
明确声明为无符号。
现在,我与某人讨论了将 int 类型的值 -1
转换为 unsigned char
时会发生什么。他拒绝将结果 unsigned char
的所有位都设置为 1 的想法,因为他担心符号表示。但他不必如此。转换会立即遵循此规则:
如果新类型是无符号的,则在新类型可以表示的最大值的基础上反复加减一,直到该值在新类型的范围内。 (C99 草案中的 6.3.1.3p2)
这是一个数学描述。 C++ 用模演算来描述它,这产生了相同的规则。无论如何,不保证的是整数 -1
中的所有位在转换之前都是 1。那么,我们有什么可以声称得到的 unsigned char
的所有 CHAR_BIT
位都变为 1?
所有位都参与确定其值 - 也就是说,对象中不会出现填充位。只加一次 UCHAR_MAX+1 到 -1 将产生一个范围内的值,即 UCHAR_MAX
够了,真的!因此,无论何时您想拥有一个所有位都为一的 unsigned char
,您可以
unsigned char c = (unsigned char)-1;
还可以看出,转换不仅仅是截断高阶位。二进制补码的幸运之处在于它只是一个截断,但对于其他符号表示不一定如此。
UCHAR_MAX
?
(unsigned type)-1
是某种成语。 ~0
不是。
int x = 1234
和 char *y = &x
的东西。 1234
的二进制表示是 00000000 00000000 00000100 11010010
。我的机器是小端的,所以它将它反转并存储在内存中 11010010 00000100 00000000 00000000
LSB 排在第一位。现在主要部分。如果我使用 printf("%d" , *p)
。 printf
将读取第一个字节 11010010
只有输出是 -46
但 11010010
是 210
那么为什么要打印 -46
。我真的很困惑,我猜一些字符到整数的提升正在做某事,但我不知道。
例如 unsigned char 的用法:
unsigned char
经常用在计算机图形中,它经常(但不总是)为每个颜色分量分配一个字节。通常看到 RGB(或 RGBA)颜色表示为 24(或 32)位,每个位是 unsigned char
。由于 unsigned char
值在 [0,255] 范围内,因此这些值通常被解释为:
0 表示完全没有给定的颜色分量。
255 表示给定颜色颜料的 100%。
所以你最终会得到 RGB 红色为 (255,0,0) -> (100% red, 0% green, 0% blue)。
为什么不使用 signed char
?算术和位移成为问题。如前所述,signed char
的范围基本上移动了 -128。将 RGB 转换为灰度的一种非常简单且幼稚(大部分未使用)的方法是对所有三个颜色分量进行平均,但是当颜色分量的值为负时,这会遇到问题。使用 unsigned char
算术时,红色 (255, 0, 0) 的平均值为 (85, 85, 85)。但是,如果值是 signed char
s (127,-128,-128),我们最终会得到 (-99, -99, -99),在我们的 {3 } 空间,这是不正确的。
signed char
的范围为 -128 到 127; unsigned char
的范围为 0 到 255。
char
将等效于有符号字符或无符号字符,具体取决于编译器,但它是一种不同的类型。
如果您使用 C 风格的字符串,只需使用 char
。如果您需要将字符用于算术(非常罕见),请显式指定有符号或无符号以实现可移植性。
unsigned char
只取正值....例如 0 到 255
然而
signed char
接受正值和负值....例如 -128 到 +127
char
和 unsigned char
不保证在所有平台上都是 8 位类型 - 它们保证是 8 位或更大。一些平台有 9-bit, 32-bit, or 64-bit bytes。但是,当今最常见的平台(Windows、Mac、Linux x86 等)具有 8 位字节。
unsigned char
是无符号字节值(0 到 255)。您可能认为 char
是一个“字符”,但它实际上是一个数值。常规 char
是有符号的,因此您有 128 个值,这些值使用 ASCII 编码映射到字符。但无论哪种情况,您在内存中存储的是一个字节值。
char
不保证是一个字节。
就直接值而言,当已知值介于 CHAR_MIN
和 CHAR_MAX
之间时,使用常规 char,而 unsigned char 在正端提供两倍的范围。例如,如果 CHAR_BIT
为 8,则正则 char
的范围仅保证为 [0, 127](因为它可以有符号或无符号),而 unsigned char
将是 [0, 255] 和 {6 } 将是 [-127, 127]。
就其用途而言,标准允许将 POD 对象(普通旧数据)直接转换为无符号字符数组。这允许您检查对象的表示和位模式。 char 或signed char 不存在相同的安全类型双关语保证。
unsigned char
的 序列,而不是具体的 数组,&任何“转换”只能通过从对象复制到unsigned char
& 的真实声明的array 来正式定义。然后检查后者。尚不清楚 OR 是否可以直接重新解释为这样的数组,允许指针算术它需要,即在这种用法中是否“序列”==
“数组”。有一个核心问题#1701 打开,希望得到澄清。谢天谢地,因为这种模棱两可最近真的困扰着我。
unsigned char
,然后从那里继续使用 ++ptr
来读取它的每个字节......但是 AFAICT ,它没有被明确定义为允许,因此我们只能从标准,类似于拼图游戏。这并不理想。好吧,也许措辞最终会有所改善。这是我提到的 CWG 问题,但缺少链接空间 - open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1701
如果您喜欢使用各种类型的特定长度和符号,那么使用 uint8_t
、int8_t
、uint16_t
等可能会更好,因为它们完全按照他们所说的做。
unsigned char
是所有诡计的核心。在所有平台的几乎所有编译器中,unsigned char
只是一个字节和一个(通常)8位的无符号整数,可以被处理作为一个小整数或一组位。
此外,正如其他人所说,该标准没有定义字符的符号。因此,您有 3 种不同的 char
类型:char
、signed char
、unsigned char
。
一些谷歌搜索发现了 this,人们对此进行了讨论。
无符号字符基本上是一个字节。因此,如果您需要一个字节的数据(例如,您可能想使用它来设置标志打开和关闭以传递给函数,就像在 Windows API 中经常做的那样),您会使用它。
unsigned char 使用为常规 char 的符号保留的位作为另一个数字。这会将范围更改为 [0 - 255],而不是 [-128 - 127]。
当您不想要符号时,通常使用无符号字符。在将 char 作为字节处理而不是将其用作数字时,这将在执行诸如移位(移位扩展符号)之类的事情和其他事情时产生影响。
unsigned char
只取正值:0 到 255,而 signed char
取正值和负值:-128 到 +127。
引用自“c 编程语言”一书:
限定符 signed
或 unsigned
可以应用于 char 或任何整数。无符号数始终为正数或零,并遵守算术模 2^n 的定律,其中 n 是类型中的位数。因此,例如,如果 char 是 8 位,则 unsigned char 变量的值介于 0 和 255 之间,而有符号 char 的值介于 -128 和 127 之间(在二进制补码机器中)。普通字符是有符号还是无符号是机器- 依赖,但可打印的字符始终为正数。
signed char
和 unsigned char
都代表 1 个字节,但它们的范围不同。
Type | range
-------------------------------
signed char | -128 to +127
unsigned char | 0 to 255
在signed char
中如果我们考虑char letter = 'A'
,'A'表示ASCII/Unicode
中65的二进制,如果可以存储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
char
不保证是一个字节,并且 signed char
只保证保持范围 [-127,127](尽管几乎所有系统都使用二进制补码并至少保持 [-128,127])
sizeof
之后放置一个空格很常见,因为它不是函数而是运算符。在获取变量的大小时,省略括号是一种更好的风格。sizeof *p
或sizeof (int)
。如果它适用于类型或变量,这将很快清楚。同样,在return
后面加上括号也是多余的。这不是一个函数。