Инициализировать вектор ‹char› значениями int

Я хочу инициализировать этот вектор символов с помощью этих кодов ASCII:

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

и я получаю эту синтаксическую ошибку во всех 6 символах:

Недопустимое сужающее преобразование из "int" в "char": постоянное значение не подходит для целевого типа.

но когда я инициализирую одну переменную char с теми же кодами ASCII:

char b = 201;

Это работает нормально.

Так я понял, что в векторах по какой-то причине тип char может принимать значения int до 127. Начиная со 128 появляется синтаксическая ошибка.

Это отличается от обычных переменных, когда тип char может принимать любые значения int.

Я попытался объявить вектор как unsigned char, и синтаксическая ошибка исчезла.

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

Но все равно,

Почему векторы типа char не могут получать те же данные int, что и переменные типа char?

Я действительно был бы признателен, если бы кто-нибудь объяснил мне это поведение.


person Walter S. Escobedo    schedule 21.12.2017    source источник
comment
Если это обычный символ, вы не можете пройти дальше 126. Работало ли это с беззнаковыми символами?   -  person Jake Freeman    schedule 22.12.2017
comment
так почему char b=201 работает?   -  person Walter S. Escobedo    schedule 22.12.2017
comment
Это дает вам ошибку компилятора переполнения   -  person Jake Freeman    schedule 22.12.2017
comment
я сомневаюсь, почему: char b=201; работает, и почему vector ‹char› b ={201}; не Почему я получаю эту ошибку с векторами, а не с обычными переменными.   -  person Walter S. Escobedo    schedule 22.12.2017
comment
Что значит char b = 201 работает? Потому что вы не получаете предупреждение компилятора?   -  person smac89    schedule 22.12.2017
comment
точно. и я могу выделить символ, назначенный на 201, который является специальным.   -  person Walter S. Escobedo    schedule 22.12.2017
comment
Перейдите к своему компилятору, и после того, как вы сделаете char b=201, вы должны добавить ниже этого std::cout << "Char c equals 201? " << std::boolalpha << (c == 201) << std::endl; и посмотреть, что вы получите   -  person smac89    schedule 22.12.2017
comment
Более того, в следующий раз при компиляции кода обязательно используйте флаг -pedantic. Использование этого флага предупредит вас об этом переполнении, которое вы считали нормальным.   -  person smac89    schedule 22.12.2017
comment
интересно. Поэтому я не получаю предупреждения. И почему, если я теряю данные, я все равно могу напечатать символ кода ASCII, который я ожидал?   -  person Walter S. Escobedo    schedule 22.12.2017
comment
Стандарт ASCII определяет только символы в диапазоне [0,127]. Все, что выше, является одним из многих, многих расширений ASCII; как ни странно, многие из них называются «расширенными ASCII», хотя ни одно из них не является официальным расширением. Это не повлияет на вашу программу, потому что, что касается языка C, все, что умещается в один байт, может быть сохранено в char, и на самом деле разница не так уж важна.   -  person Daniel H    schedule 22.12.2017


Ответы (2)


Происходят две вещи.

1
Первый — это диапазон значений по умолчанию для типа char, который определяется реализацией. В большинстве основных компиляторов значение по умолчанию — [-128,127]. (И, как ни странно, это не то же самое, что signed char, JSYK!)

И MSVC, и GCC предоставляют опции для обработки char как подписанного или неподписанного. Вы можете сделать это, чтобы решить проблему глобально.

Однако лучше не предполагать, что char обрабатывает что-либо за пределами диапазона [0,127]. Используйте signed char или unsigned char, чтобы уточнить.

2
Во-вторых, вы используете инициализацию фигурных скобок, что требует литеральные значения элементов должны быть проверены на соответствие диапазону.

Для ваших примеров:

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

char x { 201 };  // compiler error

char x = 201;  // compiler warning

Если у вас не установлен уровень ошибок вашего компилятора (а вы должны), тогда компилятор молча проигнорирует это предупреждение и присвоит значение, даже если оно технически недействительно.

person Dúthomhas    schedule 22.12.2017
comment
Спасибо!! Это действительно очень помогло. Последнее сомнение. Я понимаю, что если компилятор присвоит значение несмотря на то, что in не подходит, я потеряю данные. Почему я все еще получаю персонажа, которого ожидал? (код ASCII = 201) в этом примере. - person Walter S. Escobedo; 22.12.2017
comment
@WalterS.Escobedo Компилятор будет выполнять перенос в пределах диапазона chars (это не гарантируется, но почти все компиляторы делают это при преобразовании из int). Таким образом, он присваивает значение -55. Это тот же базовый байт, что и положительный 201, и когда вы записываете его, он точно так же отправляется на экран. - person Daniel H; 22.12.2017
comment
Спасибо, Дэниел Х. Это действительно очень помогло! - person Walter S. Escobedo; 22.12.2017

Для этого нет встроенного способа, поскольку символьные литералы заключаются только в одинарные кавычки, а числа (без суффиксов) представляют собой целые числа. Вы можете добавить L, LL, UL, ULL, чтобы сделать литеральные версии long, long long и unsigned, а также некоторые другие для чисел с плавающей запятой и т. д., но такого суффикса не существует для символов.

Однако, если у вас есть компилятор C++11 или более поздней версии, вы можете написать свой собственный пользовательский литерал, чтобы помочь с этим:

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 };
}

Если это не вариант или вам это просто не нравится, вы всегда можете написать обычную функцию, чтобы сделать что-то подобное:

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) };
}
person Chris Uzdavinis    schedule 21.12.2017
comment
Вы только что определили оператор _c? Прохладный - person smac89; 22.12.2017
comment
@ smac89 в этом нет необходимости - person Jake Freeman; 22.12.2017
comment
спасибо за ответ, но меня больше интересует поведение типа char. почему char b=201 ; работает, а почему vector <char> b ={201}; нет? - person Walter S. Escobedo; 22.12.2017
comment
Это неправда. Можно преобразовать int в char без нового оператора или функции (как видно из того факта, что вы можете написать функцию). Это также не избавляет от проблем с преобразованием чего-то вне диапазона; ваше поведение по-прежнему определяется реализацией. Наконец, он не отвечает на вопрос: не сказано, почему char b = 201 работает, а char b{201} и std::vector<char> v = { 201 } нет. - person Daniel H; 22.12.2017
comment
@WalterS.Escobedo Это потому, что {201} неукрашенный числовой литерал имеет тип int. Когда вы помещаете его в символ, вы меняете тип. - person Chris Uzdavinis; 22.12.2017
comment
@DanielH Я не говорил, что конвертировать без оператора или функции невозможно; Я сказал, что в исходном коде невозможно написать буквальное числовое значение типа 'char'. Конечно, можно привести int к char, но это необходимо только потому, что это НЕ char в первую очередь (без приведения). - person Chris Uzdavinis; 22.12.2017
comment
@ChrisUzdavinis Вы сказали: «Нет встроенного способа сделать это». ОП никогда не спрашивал о том, чтобы литерал имел тип char; они спросили о присвоении значений из литерала в char, что можно сделать. - person Daniel H; 22.12.2017