【发布时间】:2018-06-24 20:26:38
【问题描述】:
C++ 如何处理有符号字符的负值计数?行为是否在 C++11 标准中定义?我正在使用 MinGW C++ 11 编译器。它看起来通过添加 256 将有符号值转换为无符号类型,然后打印扩展的 ASCII 字符。
signed char a=-35;
std::cout<<a;
【问题讨论】:
C++ 如何处理有符号字符的负值计数?行为是否在 C++11 标准中定义?我正在使用 MinGW C++ 11 编译器。它看起来通过添加 256 将有符号值转换为无符号类型,然后打印扩展的 ASCII 字符。
signed char a=-35;
std::cout<<a;
【问题讨论】:
根据this,选择如下重载:
template< class Traits >
basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& os,
signed char ch );
由于signed char 不是char,a 首先使用widen 转换为char:
char_type widen( char c ) const;
所以你的代码相当于:
std::cout << std::cout.widen(c);
// or:
std::cout << std::use_facet< std::ctype<char> >(getloc()).widen(c)
如您所见,widen 采用char,因此您将在实际“扩大”之前从signed char 转换为char。
即使您从char 扩大到char,行为也是由实现定义的——标准对此不做任何保证。
【讨论】:
?。终端上显示的内容取决于您的终端编码。程序可能会写-35,而你的系统会将其解释为221。
-35 的二进制表示写入与std::cout 关联的流。现在,如何在另一端解释这个二进制值取决于您的系统。您的系统可能会读取二进制表示,将其解释为 221,并在终端中定义的字符集中显示相应的字符。
使用类型转换为int...
std::cout << (int)a;
...或者,遵循更好的 C++ 编程风格(正如 Christian Hackl 建议的那样):
std::cout << static_cast<int>(a);
这实际上并没有回答你的问题(霍尔特已经回答了),但显示了问题的解决方案。
【讨论】:
static_cast?
std::cout << +a,它还有一个额外的好处,就是为任何整数或浮点类型做“正确的事情”。
其中大部分是必需的行为(而且大部分还不是必需的)。
具体来说,C++ 标准说 iostream 与 C 风格的输入和输出流相关联,因此 cout 与 stdout 相关联(§[narrow.stream.objects]/3):
对象
cout控制输出到与stdout中声明的对象stdout关联的流缓冲区。
反过来,C 标准将窄字符输出定义为好像是通过 fputc 编写的(第 7.19.3/12 节):
字节输出函数将字符写入流,就像通过连续调用
fputc函数一样。
fputc 需要 (§7.19.7.3/2):
fputc函数将c指定的字符(转换为unsigned char)写入stream指向的输出流,[...]
所以,是的,转换为unsigned char 正是标准所要求的。 C 标准要求从有符号到无符号(任何整数类型,包括char)的转换以下列方式进行(第 6.3.1.3/2 节):
否则,如果新类型是无符号的,则在新类型可以表示的最大值的基础上反复加减一,直到该值在新类型的范围内。
所以是的,它通过添加 256 转换为无符号(假设 unsigned char 可以表示从 0 到 255 的值,这是典型的)。
所以这给我们留下了标准类型尝试需要的一部分,而不是一路走来——widen 必须做的转换(§[locale.ctype.virtuals]/10):
应用从一个 char 值或 char 值序列到相应的一个或多个 charT 值的最简单合理的转换。
由于要确切地确定什么是“合理的”有点困难,所以这可以对你的角色进行或多或少的任意映射。事实上,它显然是在不加修改的情况下将输入映射到输出(至少对于您正在编写的特定角色而言),但确实其他转换可能属于“合理”范围,并且最终很难划定一条强硬线说任何特定的转变都不“合理”。
C++(或任何其他)标准并不真正要求的另一部分是其他东西将如何解释该输出。所有语言标准都可以强制要求写入流的内容。其他东西打开该流并将其内容解释为“扩展 ASCII”(可能是 ISO 8859 变体之一)的部分显然超出了语言的控制范围(当然,或者您程序中的大部分其他内容)。
【讨论】:
std::cout 的输出是通过调用 fputc 来管理的?因为std::cout 与stdout 相关联并不意味着std::cout 的所有输出都由fputc 管理,就像C 中的stdout 一样。我在C++ 标准中唯一能找到的东西与@ 有关987654321@ 接受 char 而不是 unsigned char。
stdout 并且所有到stdout 的输出都是(好像)通过fputc 写入的,所有来自 C++ 的输出必须(好像)通过fputc。
fputc一样写入流,但这并不意味着 C++ 函数可以。当我阅读您的答案时(也许我遗漏了一些东西),我了解 "std::cout 和 stdout 使用相同的输出缓冲区,stdout 上的 C 操作就像通过 fputc 一样,所以在std::cout 也必须是。”,但这似乎不对。
stdout 相关联,而不仅仅是stdout 控制的缓冲区。因为cout 是char 的实例化,所以cout 的charT 是char。因此,cout 将字节写入stdout,这(在此重复)必须像fputc 那样完成。我知道你不想承认你的答案大部分是错误的,但你开始扭曲语言以保护你的错误。
stdout 关联并由std::cout 使用的实现定义的streambuf 具有要使用这些函数写入stdout,它可能会使用低级例程。