Можно ли объединить строковый литерал и символьный литерал?

StackOverflow https://stackoverflow.com/questions/635807

  •  10-07-2019
  •  | 
  •  

Вопрос

Почему это происходит 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 " литерал хранится в памяти.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top