39

考虑以下代码:

#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 

这意味着intandsigned int被认为是同一类型,但不是charand signed char。这是为什么 ?

如果我可以将 achar转换为signed charusing make_signed,如何做相反的事情(将 a 转换signed char为 a char)?

4

4 回答 4

28

它是设计使然,C++ 标准charsigned char并且unsigned char是不同的类型。我认为您可以使用静态转换进行转换。

于 2013-05-12T01:45:06.020 回答
28

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

在无符号类型中,所有位都表示值。例如,一个 8 位无符号字符可以保存从 0 到 255 的值(包括 0 到 255)。

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


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

使用char的计算通常是有问题的。Char 默认在某些机器上签名,而在其他机器上未签名。所以我们不应该在算术表达式中使用 (plain) char 。仅用于保存字符。如果您需要一个小整数,请明确指定有符号字符无符号字符

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

于 2015-07-11T05:16:58.157 回答
9

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

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

于 2014-10-27T11:16:59.693 回答
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ⁿ⁻¹ 到 2ⁿ⁻¹-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 的值来执行指针的算术运算。

于 2020-04-30T19:09:36.557 回答