Непонятное поведение оператора + при инициализации строки
На какое-то время забросил плюсы. А теперь решил попрактиковаться и "въехал в пень". Есть вот такой код
#include <iostream>
#include <string>
int main()
{
char c = '\20';
std::string s = "qreqwerqw" + c;
std::cout << s << '\n';
return 0;
}
И есть резутьтат/вывод, который я так и не понял, как получается
Выыод GCC:
basic_string: construction from null is not valid
Выыод Clang:
string: construction from null is not valid
https://godbolt.org/z/crxeT9czz
Clang выдаёт предупреждение
<source>:7:33: warning: adding 'char' to a string does not append to
the string [-Wstring-plus-int]
7 | std::string s = "qreqwerqw" + c;
| ~~~~~~~~~~~~^~~ <source>:7:33: note: use array indexing to silence this warning
7 | std::string s = "qreqwerqw" + c;
| ^
| & [ ]
и вроде как понятно, что я пытаюсь сложить "метры" с "килограммами", и что причина в магии адресной арифметики. Но я не совсем понимаю, как в итоге в конструктор строки попал какой-то адрес из тела программы.
Правильно ли я понимаю?: Произошло автоматическое приведение массива char[] к указателю char* на его начало и к этому адресу прибавилось число (потому что char - это тоже числовой тип). И в итоге получили новый адрес. А так как строковый литерал обязан иметь размещение своего адреса, то он был размещен в тексте программы. И этот новый адрес тоже оказался на какое-то место в тексте программы со смещением от константы литерала.
*Добавлено -----------
Но если это так, не понимаю, почему это в принципе работает на всех компиляторах? (MS VisualStudio выдёт такое же) Ведь здесь компилятору нужно не просто выполнить автоприведение, а выполнить автоприведение результата метода, для вызова которого нужно выполнить автоприведение. Я думал стандарт не разрешает таких цепочек.
Ответы (2 шт):
Забавное сравнение компиляторов вышло.
...и вроде как понятно, что я пытаюсь сложить "метры" с "килограммами", и что причина в магии адресной арифметики.
Это не так, Вы складываете const char * с целочисленным типом char, результат имеет тип const char *. Всё строго по стандартам C/C++.
Для значений в диапазоне от '\00' до '\11' всё более менее. Правда, clang считает это плохим стилем, но это ж вкусовщина.
А начиная с '\12' - это UB (Undefined Behaviour), и программа начинает нести пургу, к примеру, для \13 clang даёт код выдающий "asic_string: construction from null is not valid", а для '\40' код gcc выдаёт "nstruction from null is not valid".
P.S.
(MS VisualStudio выдёт такое же)
Не знаю, не знаю, но если в Compiler Explorer выбрать "x64 msvc v19.latest", он выдаст "честные": "���8�" ?
std::string s = "qreqwerqw" + c;
К char* прибавляется char, приведенный к int для адресной арифметики. Результат показать не могу, потому что это указатель на что-то далеко за строкой (и автоматически приводит к UB). И этот результат используется для инициализации строки (передается в конструктор).
std::string s = std::string("qreqwerqw") + c;
К string прибавляется char, а этот оператор уже работает иначе, действительно "дописывая" символ к строке.