Можно ли объединить строковый литерал и символьный литерал?
Вопрос
Почему это происходит name
плохо себя ведете в следующем коде на C ++?
string name = "ab"+'c';
Как бы вел себя эквивалентный код в Java / C #?
Решение
Попробуйте
std::string name = "ab" "c";
или
std::string name = std::string("ab") + c;
В C ++ " ab " это не std::string
, а скорее указатель на строку символов. Когда вы добавляете целое значение к указателю, вы получаете новый указатель, который указывает дальше по строке:
char *foo = "012345678910121416182022242628303234";
std::string name = foo + ' ';
name
устанавливается в " 3234 ", поскольку целочисленное значение '' равно 32, а 32 символа после начала foo - это четыре символа до конца строки. Если строка была короче, вы пытались бы получить доступ к чему-либо на неопределенной территории памяти.
Решением этой проблемы является создание строки std: из массива символов. std: строки позволяют добавлять символы к ним, как и ожидалось:
std::string foo = "012345678910121416182022242628303234";
std::string name = foo + ' ';
<=> устанавливается в " 012345678910121416182022242628303234 "
Другие советы
Проблема в том, что " ab " это не C ++ std::string
, а const char[3]
.
Таким образом, оператор +, который он ищет, это operator+ (const char[3], char)
. Этого не существует, поэтому компилятор пытается позволить массиву распадаться на указатель, поэтому он ищет operator+ (const char*, char)
. Это существует, поэтому компилятор выбирает это, но делает не то, что нужно. Добавление целочисленного значения (char) к указателю (const char *) является достаточно распространенной операцией, и, очевидно, это то, что делает этот оператор +. Ключом к пониманию этого является понимание того, что первый аргумент - это 1) массив и 2) указатель, когда массив не имеет смысла. Да, она также использовалась как строка в C, но это не строка. Это указатель (или иногда массив).
Существует operator+ (const std::string&, char)
, который объединяет, но компилятор даже не ищет его, потому что первый аргумент не является std :: string.
Таким образом, решение состоит в том, чтобы вручную создать строку:
string name = std::string("ab")+'c';
Теперь компилятор может определить правильный оператор + для вызова.
В C ++ компилятор ищет функцию с этим прототипом:
T operator+ (const char*, char);
Поскольку его нет, он не может понять, что такое T, и не может разрешить вызов operator<<
, поэтому он прибегает к единственному оставленному решению: добавлению указателя. В ответе Джоша нет проблем с привязкой к строке, поскольку для нее существует функция.
Учитывая код C ++:
std::string name = "ab"+'c';
Эквивалент в Java:
String name = "ab".substring('c');
Оба продвигают char к int. Конечно, в Java он проверяет диапазон и, следовательно, выдает исключение. В C ++ вы просто получаете неопределенное поведение (или что-то подобное).
Java:
public class Main
{
public static void main(String[] args)
{
System.out.println("AB" + 'c');
}
}
Результат равен:
Азбука
Редактировать:
На самом деле компилятор жестко кодирует строку ABc...
Если вы сделаете "AB" + argv[0].charAt(0);чтобы заставить его использовать переменную, компилятор делает это (в основном):
StringBuilder b = new StringBuilder;
b.append("AB");
b.append(argv[0].charAt(0));
System.out.println(b.toString());
Вы можете объединять строки и символы в C # - я думаю, это не так строго, как в C ++.
Это прекрасно работает в C #:
string test = "foo" + 'b';
Компилятор C ++ автоматически не объединяет строковые литералы с символьными литералами. Но он объединит строковые литералы друг с другом. Синтаксис такой:
const char * cs = "ab" "c"; // append string-literals
Как уже упоминалось, string
не является встроенным языковым типом C ++. Но в стандартной библиотеке C ++ есть тип <=>. Вот несколько примеров использования:
#include <string>
const char * cs = "ab" "c";
std::string s1( cs );
std::string s2( "ab" "c" );
std::string s3 = "ab" "c";
Что я обычно делал бы в C ++, так это
string name = string (" ab ") + 'c';
Помните, что буквальное " ab " не типа строки. Вы надеялись, что & Quot; + & Quot; это работает между массивами символов и символами, а затем надеется, что компилятор каким-то образом заметит, что вы действительно хотите, чтобы результат был std :: string, а затем проанализировал свое выражение с правой стороны для некоторой комбинации неявных преобразований, которые могли бы объединить с оператором (ами) для получения результата этого типа. Похоже, довольно высокий заказ для меня.
Несмотря на это, это не имеет значения. Видите ли, в Си единственная разница между массивом и указателем заключается в том, как распределяется их память. Если он у вас есть, то у вас, по сути, есть & Quot; array / pointer вещь & Quot ;. Таким образом, & Quot; + & Quot; является оператором, определенным для всех массивов и указателей, который принимает другой аргумент любого целочисленного типа и выполняет математику указателя, возвращая указатель на то множество элементов, которые находятся за этой точкой. Также в C & Quot; char & Quot; на самом деле просто еще один вид целочисленного типа. Эти решения по проектированию на Си были полезными взломами , но, как это часто бывает с взломами, они сочетаются с интуитивно неожиданными результатами. Так что все & Quot; ab & Quot; + 'c' делает для вас возвращение адреса на 99 байтов после везде, где " ab " литерал хранится в памяти.
Иногда вы можете положиться на неявные преобразования, но вам действительно нужно быть готовым помочь вашему компилятору немного в другое время.