Mutating Algorithm
Mutating Algorithm

Reputation: 2758

Under what circumstances would one use a signed char in C++?

In most situations, one would declare a char object to assign one of the character values on the ascii table ranging from 0 - 127. Even the extended character sets range from 128 - 255 (still positive). So i'm assuming that when dealing with the printing of characters, one only needs to use an unsigned char.

Now, based on some research on SO, people use a signed char when they need to use really small integers, but for that we can utilize the [u]int8 type. So i'm having trouble coming to terms with why one would need to use a signed char ? You can use it if you are dealing with the basic character ascii table (which unsigned char is already capable of doing) or you can use it to represent small integers (which [u]int8 already takes care of).

Can someone please provide a programming example in which a signed char is preferred over the other types ?

Upvotes: 30

Views: 5505

Answers (3)

Filip Roséen
Filip Roséen

Reputation: 63902

Is char signed or unsigned?

Actually it is neither, it's implementation defined if a variable of type char can hold negative values. So if you are looking for a portable way to store negative values in a narrow character type explicitly declare it as signed char.

§ 3.9.1 - Fundamental Types - [basic.fundamental]

1 Objects declared as characters (char) shall be large enough to store any member of the implementation's basic character set. If a character from this set is stored in a character object, the integral value of that character object is equal to the value of the single character literal form of that character. It is implementation-defined whether a char object can hold negative values.


I'd like to use the smallest signed integer type available, which one is it?

c++11 introduced several fixed with integer types, but a common misunderstanding is that these types are guaranteed to be available, something which isn't true.

§ 18.4.1 - Header <cstdint> synopsis - [cstdint.syn]

typedefsigned integer typeint8_t; // optional

To preserve space in this post most of the section has been left out, but the optional rationale applies to all {,u}int{8,16,32,64}_t types. An implementation is not required to implement them.


The standard mandates that int_least8_t is available, but as the name implies this type is only guaranteed to have a width equal or larger than 8 bits.

However, the standard guarantees that even though signed char, char, and unsigned char are three distinct types[1] they must occupy the same amount of storage and have the same alignment requirements.

After inspecting the standard further we will also find that sizeof(char) is guaranteed to be 1[2] , which means that this type is guaranteed to occupy the smallest amount of space that a C++ variable can occupy under the given implementation.


Conclusion

Remember that unsigned char and signed char must occupy the same amount of storage as a char?

The smallest signed integer type that is guaranteed to be available is therefore signed char.



[note 1]

§ 3.9.1 - Fundamental Types - [basic.fundamental]

1 Plain char, signed char, and unsigned char are three distinct types, collectively called narrow character types.

A char, a signed char, and an unsigned char occupy the same amount of storage and have the same alignment requirements (3.11); that is, they have the same object representation. For narrow character types, all bits of the object representation participate in the value representation.

[note 2]

§ 5.3.3 - Sizeof - [expr.sizeof]

sizeof(char), sizeof(signed char), and sizeof(unsigned char) are 1.

The result of sizeof applied to any other fundamental type (3.9.1) is implementation-defined.

Upvotes: 13

Filipe Gon&#231;alves
Filipe Gon&#231;alves

Reputation: 21233

The reason is that you don't know, at least portably, if plain char variables are signed or unsigned. Different implementations have different approaches, a plain char may be signed in one platform and unsigned in another.

If you want to store negative values in a variable of type char, you absolutely must declare it as signed char, because only then you can be sure that every platform will be able to store negative values in there. Yes, you can use [u]int8 type, but this was not always the case (it was only introduced in C++11), and in fact, int8 is most likely an alias for signed char.

Moreover, uint8_t and int8_t are defined to be optional types, meaning you can't always rely on its existence (contrary to signed char). In particular, if a machine has a byte unit with more than 8 bits, it is not very likely that uint8_t and int8_t are defined (although they can; a compiler is always free to provide it and do the appropriate calculations). See this related question: What is int8_t if a machine has > 8 bits per byte?

Upvotes: 26

Nikos Athanasiou
Nikos Athanasiou

Reputation: 31597

You can use char for arithmetic operations with small integers. unsigned char will give you greater range, while signed char will give you a smaller absolute range and the ability to work with negative numbers.

There are situations where char's small size is of importance and is preffered for these operations, see here, so when one has negative numbers to deal with, signed char is the way to go.

Upvotes: 5

Related Questions