char is an arithmetic type, but it rarely makes sense to treat it as one, because its signedness is implementation-defined. If you want a very narrow integer type, both signed char and unsigned char are arithmetic types, and can reasonably be used that way. (Arrays of unsigned char are also used for raw memory.)
And you should understand how char, signed char, and unsigned char behave when you do use them as arithmetic types.
Promotion to int or unsigned int, depending on the range of the type, can be confusing. The same applies to all integer types with lower rank than int, including short, unsigned short, and intN_t and uintN_t for N==8 (and probably for N==16, and maybe for larger N).
Note also that this:
char c = '0';
++c;
is guaranteed to set c to '1'. (This guarantee applies only to decimal digits, not to letters.) #include <type_traits>
static_assert(std::is_arithmetic<char>::value, "char is arithmetic");[1] int8_t is not required.
[2] char is the fundamental unit of addressability. sizeof char always evaluates to 1, sizeof int8_t must be non-0, char must be at least 8 bits, and int8_t must be precisely 8 bits, therefore sizeof int8_t == sizeof char and CHAR_BIT == 8.