Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initialize vector <char> with int values

I want to initialize this char vector with this ASCII codes:

vector <char> a = { 201, 187, 200, 188, 205, 186 };

and I get this syntax error in all of the 6 characters:

Invalid narrowing convertion from "int" to "char": constant value does not fit in destination type

but when I initialize a single char variable, with the same ASCII codes:

char b = 201;

It works fine.

So I realized that in vectors, for some reason, char type can receive int values until 127. Starting 128 the syntax error appears.

This is different than in normal variables, when char type can receive any int values.

I tried declaring the vector as unsigned char, and the syntax error dissapears.

vector <unsigned char> a = { 201, 187, 200, 188, 205, 186 };

But still,

Why char type vectors cannot receive the same int data as char type variables?

I really would appreciate someone explaining me this behavior.

like image 726
Walter S. Escobedo Avatar asked Dec 19 '22 02:12

Walter S. Escobedo


2 Answers

There are two things going on.

1
The first is the default range of values for the char type, which is implementation defined. In most major compilers the default is [-128,127]. (And, oddly, this is not the same as signed char, JSYK!)

Both MSVC and GCC provide options to treat char as signed or unsigned. You can do that to fix the problem globally.

Better, though, is not to assume char handles anything outside the range [0,127]. Use signed char or unsigned char to be specific.

2
The second is that you are using brace initialization, which requires that literal element values be checked for range fit.

For your examples:

std::vector <char> xs = { 201, 202 };  // compiler error

char x { 201 };  // compiler error

char x = 201;  // compiler warning

If you don’t have your compiler’s error level cranked up (and you should) then the compiler will silently ignore that warning and assign the value, even though it is technically invalid.

like image 157
Dúthomhas Avatar answered Dec 24 '22 02:12

Dúthomhas


There is no built-in way to do that, because character literals are in single quotes only, and numbers (without suffixes) are ints. You can add a L, LL, UL, ULL to make a literal long, long long, and unsigned versions, plus some other for floating points, etc., but no such suffix exists for chars.

However, if you have a C++11 or later compiler, you can write your own user-defined literal to help with this:

constexpr char operator "" _c(unsigned long long arg) noexcept
{
    return static_cast<char>(arg);
}

int f()
{
  std::vector <char> a = { 201_c, 187_c, 200_c, 188_c, 205_c, 186_c };
}

If this isn't an option or you just don't like it you could always write an ordinary function to do something similar:

constexpr char c(int arg) noexcept
{
    return static_cast<char>(arg);
}

int f()
{
  std::vector <char> a = { c(201), c(187), c(200), c(188), c(205), c(186) };
}
like image 41
Chris Uzdavinis Avatar answered Dec 24 '22 01:12

Chris Uzdavinis