简体   繁体   中英

How to check if plain chars are signed or unsigned?

Apparently there is a possibility that plain char can be either signed or unsigned by default. Stroustrup writes:

It is implementation-defined whether a plain char is considered signed or unsigned. This opens the possibility for some nasty surprises and implementation dependencies.

How do I check whether my chars are signed or unsigned? I might want to convert them to int later, and I don't want them to be negative. Should I always use unsigned char explicitly?

From header <limits>

std::numeric_limits<char>::is_signed

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

Some alternatives:

const bool char_is_signed = (char)-1 < 0;

#include <climits>
const bool char_is_signed = CHAR_MIN < 0;

And yes, some systems do make plain char an unsigned type. Examples I've encountered: Cray T90, Cray SV1, Cray T3E, SGI MIPS IRIX, IBM PowerPC AIX. And any system that uses EBCDIC pretty much has to make plain char unsigned so that all basic characters have non-negative values. (And some compilers have an option to control the signedness of char , such as gcc's -fsigned-char and -funsigned-char .)

But std::numeric_limits<char>::is_signed , as suggested by Benjamin Lindley's answer , probably expresses the intent more clearly.

(On the other hand, the methods I suggested can also be applied to C.)

Using unsigned char "always" could give you some interesting surprises, as the majority of C-style functions like printf , fopen , will use char , not unsigned char .

edit: Example of "fun" with C-style functions:

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

will give errors (in fact, I get one for the *cmd = line, and one error for the popen line). Using const char *cmd = ... will work fine. I picked popen because it's a function that isn't trivial to replace with some standard C++ functionality - obviously, printf or fopen can quite easily be replaced with some iostream or fstream type functionality, which generally has alternatives that take unsigned char as well as char .

However, if you are using > or < on characters that are beyond 127, then you will need to use unsigned char (or some other solution, such as casting to int and masking the lower 8 bits). It is probably better to try to avoid direct comparisons (in particular when it comes to non-ASCII characters - they are messy anyway, because there are often several variants depending on locale, character encodings, etc). Comparing for equality should work however.

Yes, if you want to use a char type and you always want it to be unsigned, use unsigned char . Note that unlike the other fundamental integer types, unsigned char is a different type from char -- even on systems where char is unsigned. Also, conversion from char to int ought to be lossless so if your result is incorrect, your source char value may also be incorrect.

The cleanest way to test whether char is unsigned depends on whether you need it to be a preprocessor test and on which version of C++ you are targeting.

To conditionally compile code using a preprocessor test, the value of CHAR_MIN should work:

#include <climits>

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

In C++17, I would use std::is_signed_v and std::is_unsigned_v :

#include <type_traits>

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

If you are writing against C++11 or C++14 you need the slightly more verbose std::is_signed and std::is_unsigned :

#include <type_traits>

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

For all revisions of C++, @benjamin-lindley's solution is a good alternative.

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM