为什么 char 与signed char 和unsigned char 不同?

问题描述 投票:0回答:4

考虑以下代码:

#include <iostream>
#include <type_traits>
 
int main()
{
    std::cout << "std::is_same<int, int>::value = " << std::is_same<int, int>::value << std::endl;
    std::cout << "std::is_same<int, signed int>::value = "<<std::is_same<int, signed int>::value << std::endl;
    std::cout << "std::is_same<int, unsigned int>::value = " << std::is_same<int, unsigned int>::value << std::endl;

    std::cout << "----" << std::endl;

    std::cout << "std::is_same<char, char>::value = " << std::is_same<char, char>::value << std::endl;
    std::cout << "std::is_same<char, signed char>::value = " << std::is_same<char, signed char>::value << std::endl;
    std::cout << "std::is_same<char, unsigned char>::value = " << std::is_same<char, unsigned char>::value << std::endl;
}

结果是:

std::is_same<int, int>::value = 1
std::is_same<int, signed int>::value = 1
std::is_same<int, unsigned int>::value = 0
----
std::is_same<char, char>::value = 1
std::is_same<char, signed char>::value = 0
std::is_same<char, unsigned char>::value = 0

这意味着

int
signed int
被视为同一类型,但
char
signed char
则不然。这是为什么?

如果我可以使用

char
signed char
转换为
make_signed
,那么如何做相反的事情(将
signed char
转换为
char
)?

c++ c++11 char signed type-traits
4个回答
33
投票

三种不同的基本字符类型:char、signed charunsigned char。 虽然有三种字符类型,但只有两种表示形式:有符号和无符号。 (plain)char 使用这些表示之一。其他两个字符表示中哪一个相当于 char 取决于编译器

在无符号类型中,所有位都代表值。例如,8 位 unsigned char 可以保存从 0 到 255(含)的值。

该标准没有定义如何表示有符号类型,但指定范围应在正值和负值之间均匀划分。因此,8 位 signed char 保证能够保存从 -127 到 127 的值。


那么如何决定使用哪种Type呢?

使用 char 的计算通常会出现问题。 Char 默认情况下在某些机器上已签名,而在其他机器上则未签名。所以我们不应该在算术表达式中使用 (plain)char。仅用它来保存字符。如果您需要一个小整数,请显式指定 signed charunsigned char

摘自C++ Primer 第 5 版,第 14 页。 66.


28
投票

这是设计使然,C++ 标准

char
signed char
unsigned char
是不同的类型。我认为你可以使用静态强制转换来进行转换。


9
投票

事实上,标准明确指出 char、signed char 和 unsigned char 是 3 种不同的类型。一个字符通常是 8 位,但这不是标准强加的。一个8位数字可以编码256个唯一值;区别仅在于如何解释这 256 个唯一值。如果将 8 位值视为有符号二进制值,则它可以表示从 -128(编码为 80H)到 +127 的整数值。如果您认为它是无符号的,它可以表示 0 到 255 的值。根据 C++ 标准,有符号的 char 保证能够保存值 -127 到 127(不是 -128!),而无符号的 char 能够保存值0 到 255。

将 char 转换为 int 时,结果是实现定义的!结果可能例如根据单个字符“É”(ISO 8859-1)的机器实现,为 -55 或 201。事实上,将字符保存在一个字(16 位)中的 CPU 可以存储 FFC9 或 00C9 或 C900,甚至 C9FF(以大端和小端表示)。对有符号或无符号字符的显式转换确实保证了 char 到 int 的转换结果。


3
投票

添加有关范围的更多信息:从 c++ 20 开始,有符号字符也保证 -128 值:P1236R0:P0907R4 有符号整数的替代措辞是二进制补码

对于有符号整数类型的每个值x,都有一个对应的无符号整数类型的唯一值y,使得x与y模2N全等,反之亦然;每个这样的 x 和 y 都有相同的表示。

[脚注:这也称为 补码表示法.].
[ 示例:有符号类型的值 -1 与相应无符号类型的值 2N-1 相同;这些值的表示是相同的。 ]

表 X 中指定了每个有符号整数类型的范围指数的实现所需支持的最小值。

我善意而痛苦地(因为SO不支持表降价)重写了下面的表x:

╔═════════════╦════════════════════════════╗  
║ Type        ║ Minimum range exponent N   ║  
╠═════════════╬════════════════════════════╣  
║ signed char ║        8                   ║  
║ short       ║       16                   ║  
║ int         ║       16                   ║  
║ long        ║       32                   ║  
║ long long   ║       64                   ║  
╚═════════════╩════════════════════════════╝  

因此,有符号字符有 8 位:-2ⁿ⁻1 到 2ⁿ⁻1-1(n 等于 8)。

保证范围是从-128到127。因此,当涉及范围时,char 和signed char 之间不再有区别。


关于 Cadoiz 的评论:标准所说的都是如此,现实也是如此。
使用以下程序进行现实检查:

#include <stdio.h>

int main(void) {
    char c = -128;
    printf("%d\n", (int)c);
    printf("%d\n", (int)--c);
    return 0;
}

输出:

-128
127

我还想说,signed char 可以帮助其他程序员,也可能帮助编译器理解您将使用 char 的值来执行指针的算术。

© www.soinside.com 2019 - 2024. All rights reserved.