请考虑以下代码:
#include <iostream>
#include <type_traits>
int main(int argc, char* argv[])
{
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::is_same<signed int, int>::value = "<<std::is_same<signed int, int>::value<<std::endl;
std::cout<<"std::is_same<signed int, signed int>::value = "<<std::is_same<signed int, signed int>::value<<std::endl;
std::cout<<"std::is_same<signed int, unsigned int>::value = "<<std::is_same<signed int, unsigned int>::value<<std::endl;
std::cout<<"std::is_same<unsigned int, int>::value = "<<std::is_same<unsigned int, int>::value<<std::endl;
std::cout<<"std::is_same<unsigned int, signed int>::value = "<<std::is_same<unsigned int, signed int>::value<<std::endl;
std::cout<<"std::is_same<unsigned int, unsigned int>::value = "<<std::is_same<unsigned 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::cout<<"std::is_same<signed char, char>::value = "<<std::is_same<signed char, char>::value<<std::endl;
std::cout<<"std::is_same<signed char, signed char>::value = "<<std::is_same<signed char, signed char>::value<<std::endl;
std::cout<<"std::is_same<signed char, unsigned char>::value = "<<std::is_same<signed char, unsigned char>::value<<std::endl;
std::cout<<"std::is_same<unsigned char, char>::value = "<<std::is_same<unsigned char, char>::value<<std::endl;
std::cout<<"std::is_same<unsigned char, signed char>::value = "<<std::is_same<unsigned char, signed char>::value<<std::endl;
std::cout<<"std::is_same<unsigned char, unsigned char>::value = "<<std::is_same<unsigned char, unsigned char>::value<<std::endl;
return 0;
}
结果是:
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<signed int, int>::value = 1
std::is_same<signed int, signed int>::value = 1
std::is_same<signed int, unsigned int>::value = 0
std::is_same<unsigned int, int>::value = 0
std::is_same<unsigned int, signed int>::value = 0
std::is_same<unsigned int, unsigned int>::value = 1
----
std::is_same<char, char>::value = 1
std::is_same<char, signed char>::value = 0
std::is_same<char, unsigned char>::value = 0
std::is_same<signed char, char>::value = 0
std::is_same<signed char, signed char>::value = 1
std::is_same<signed char, unsigned char>::value = 0
std::is_same<unsigned char, char>::value = 0
std::is_same<unsigned char, signed char>::value = 0
std::is_same<unsigned char, unsigned char>::value = 1
这意味着int
和signed int
被视为相同类型,但不是char
和signed char
。那是为什么?
如果我可以使用char
将signed char
转换为make_signed
,如何做相反的事情(将signed char
转换为char
)?< / p>
答案 0 :(得分:17)
按设计,C++ standard说char
,signed char
和unsigned char
是不同的类型。我认为你可以使用静态转换进行转换。
答案 1 :(得分:16)
三种不同的基本字符类型: char,signed char 和 unsigned char 。 虽然有三种字符类型,但只有两种表示形式:有符号和无符号。 (普通) char 使用其中一种表示形式。其他两个字符表示中的哪一个等同于 char 取决于编译器。
在无符号类型中,所有位代表值。例如,8位 unsigned char 可以保存0到255之间的值。
标准没有定义如何表示签名类型,但是指定范围应该在正值和负值之间平均分配。因此,保证8位签名字符能够保存-127到127之间的值。
那么如何决定使用哪种类型?
使用 char 进行计算通常会产生问题。默认情况下, Char 在某些计算机上签名,在其他计算机上签名。所以我们不应该在算术表达式中使用(plain) char 。仅用于保存字符。如果您需要一个小整数,请明确指定 signed char 或 unsigned char 。
答案 2 :(得分:6)
事实上,标准正在告诉char,signed char和unsigned char是3种不同的类型。 char通常是8位,但这不是标准强加的。一个8位数字可以编码256个唯一值;区别仅在于如何解释这256个唯一值。如果将8位值视为带符号二进制值,则它可以表示从-128(编码为80H)到+127的整数值。如果你认为它是无符号的,它可以表示0到255的值。根据C ++标准,有符号的char保证能够保存-127到127(不是-128!)的值,而unsigned char能够保存值0到255.
将char转换为int时,结果是实现定义的!结果可能是例如根据单一字符'''(ISO 8859-1)的机器实现,为-55或201。实际上,一个字(16位)保存字符的CPU可以存储FFC9或00C9或C900,甚至C9FF(在大端和小端表示中)。使用signed或unsigned char确保char转换为int转换结果。
答案 3 :(得分:0)
添加有关范围的更多信息:从c ++ 20开始,带符号的字符也保证了-128的值:P1236R0: Alternative Wording for P0907R4 Signed Integers are Two's Complement
对于有符号整数类型的每个值x,都有一个对应的无符号整数类型的唯一值y,以使x与y模2N相等,反之亦然;每个这样的x和y具有相同的表示。
[脚注:这也称为two's complement representation。]。
[示例:带符号类型的值-1与对应的无符号类型的值2N-1相等;这些值的表示形式相同。 ]表X中指定了实现所需的每种有符号整数类型的范围指数的最小值。
(自SO does not support markdown for table起,我恳切而痛苦地重写了下面的表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和带符号的char之间没有更多区别。
我想说带符号的char可以帮助其他程序员,也有可能使编译器了解您将使用char的值执行算术。
答案 4 :(得分:0)
在对 char、signed char 和 unsigned char 之间的差异进行非常详细的审查后,我非常感激,我想知道:
它打算解决什么问题?
在 C++ 标准中需要什么来构建如此复杂的东西?
拥有一个你不确定它是否会被签名的字符有什么好处?
想逃避那个问题,我想为这样一个疯狂的解决方案贡献我的答案:
一个字符就是一个字符,它的任务是尽可能地包含一个字符。
如果我没记错的话,一个文本字符串(例如 const char *,甚至 char [])代表的是 UTF-8 编码的文本。
如果我们将这两个概念结合起来,我们就会得到一个字符必须包含最多允许的 UTF-8 字符。而且,正如我们所知,一个字符最多可以包含为一个单独的 UTF-8 字符是 0x00 到 0x7E 范围内的代码之一。在这个范围之外,UTF-8 字符由多个字符组成,为简洁起见,2、3 和 4 个字符。不仅仅是字符,这种表示应该被称为代码点。
无论是 1、2、3 还是 4 个字符,这些代码点都没有符号,实际上最左边的位用于编码 UTF-8 代码的头部并表示它包含多少字节,或者,也可以表示字符对标头进行补充,直到完成代码点。
最终,char 是否有符号并不重要,重要的是在文本字符串的上下文中如何解释 char。