如何检查纯字符是有符号的还是无符号的

How to check if plain chars are signed or unsigned?

本文关键字:无符号 符号 字符 何检查 检查      更新时间:2023-10-16

显然,默认情况下,普通char可能是有符号的或无符号的。Stroustrup写道:

它是由实现定义的,是将纯字符视为有符号字符还是无符号字符。这将打开可能会出现一些令人讨厌的意外和实现依赖关系。

如何检查我的字符是有符号的还是无符号的?我可能想稍后将它们转换为int,但我不希望它们为负数。我应该始终显式使用unsigned char吗?

来自标头<limits>

std::numeric_limits<char>::is_signed

http://en.cppreference.com/w/cpp/types/numeric_limits/is_signed

一些替代方案:

const bool char_is_signed = (char)-1 < 0;
#include <climits>
const bool char_is_signed = CHAR_MIN < 0;

是的,有些系统确实使普通char成为无符号类型。我遇到过的例子:Cray T90、Cray SV1、Cray T3E、SGI MIPS IRIX、IBM PowerPC AIX。任何使用EBCDIC的系统都必须使纯char无符号,以便所有基本字符都具有非负值。(一些编译器可以选择控制char的签名性,例如gcc的-fsigned-char-funsigned-char。)

但正如本杰明·林德利的回答所暗示的那样,std::numeric_limits<char>::is_signed可能更清楚地表达了意图。

(另一方面,我建议的方法也可以应用于C.)

使用unsigned char"始终"可能会给您带来一些有趣的惊喜,因为大多数C风格函数(如printffopen)将使用char,而不是unsigned char

edit:C风格函数的"乐趣"示例:

const unsigned char *cmd = "grep -r blah *.txt";
FILE *pf = popen(cmd, "r"); 

将给出错误(事实上,*cmd =行和popen行分别得到一个错误)。使用const char *cmd = ...会很好。我选择popen是因为它是一个用一些标准C++功能替换的函数——显然,printffopen可以很容易地用一些iostreamfstream类型的功能替换,这些功能通常有unsigned charchar的替代品。

但是,如果对超过127的字符使用><,则需要使用unsigned char(或其他解决方案,例如强制转换为int并屏蔽较低的8位)。最好尽量避免直接比较(尤其是当涉及到非ASCII字符时——它们无论如何都很混乱,因为根据区域设置、字符编码等,通常有几种变体)。然而,平等的比较应该起作用。

是的,如果要使用char类型,并且始终希望它是无符号的,请使用unsigned char。请注意,与其他基本整数类型不同,unsigned charchar是不同的类型——即使在char为无符号的系统上也是如此。此外,从charint的转换应该是无损的,因此如果结果不正确,则源char值也可能不正确。

测试char是否未签名的最干净方法取决于您是否需要它作为预处理器测试,以及您要针对的C++版本。

要使用预处理器测试有条件地编译代码,CHAR_MIN的值应该有效:

#include <climits>
#if (CHAR_MIN==0)
// code that relies on char being unsigned
#endif

在C++17中,我将使用std::is_signed_vstd::is_unsigned_v:

#include <type_traits>
static_assert(std::is_unsigned_v<char>);
// code that relies on char being unsigned

如果您是针对C++11或C++14编写的,则需要稍微详细一点的std::is_signedstd::is_unsigned:

#include <type_traits>
static_assert(std::is_unsigned<char>::value, "char is signed");
// code that relies on char being unsigned

对于C++的所有修订,@benjamin-lindley的解决方案是一个很好的替代方案。

您可以使用预处理器命令:

 #define is_type_signed(my_type) (((my_type)-1) < 0)