Как С++ интерпретирует cout с "+" в нем?
Я двигался вперед и назад с помощью Java/С++, поэтому я испортил свой вывод на консоль и случайно написал строки, например:
cout << "num" + numSamples << endl;
cout << "max" + maxSampleValue << endl;
Каждый из них дал мне кусочки других строк, которые у меня были в моей программе. Я осознаю свою ошибку сейчас, но что такое С++, интерпретирующий эти строки так, чтобы они выводили разные части разных строк в моей программе?
Ответы
Ответ 1
Для этого есть простая причина:
"num"
и "max"
являются строковыми литералами. Их тип const char *
.
Предполагая, что numSamples
является целым числом, то, что вы делаете, является арифметикой указателя.
Вы в основном печатаете строку, которая указывает на "num"
+ numSamples
bytes.
Если вы сделали cout << "num" + 1 << endl
, это напечатает "um"
.
Вероятно, вы поняли это, но правильный способ сделать это: cout << "num" << numSamples << endl;
Кроме того, вы спросили:
Но что такое С++, интерпретирующий эти строки так, чтобы они выводили разные части разных строк в моей программе?
Как указано выше, "num"
является строковым литералом. Обычно строковые литералы сидят в одном месте в двоичной программе: .rodata
. Все остальные строковые литералы сидят в этом регионе, поэтому, когда вы продвигаете указатель на определенное количество байтов, вы, вероятно, укажете на некоторые другие строковые литералы, тем самым напечатав (часть) их.
Ответ 2
Это просто арифметика указателя. Например,
cout << "num" + 1 << endl;
будет печатать строку, смотрящую из ((address of)"num" + 1)
, т.е. "um"
.
Если добавляемое нами значение превышает длину строки, то мы имеем поведение undefined.
Ответ 3
Имейте в виду, что хотя iostreams перегружают <<
(и >>
) для ввода-вывода, они были первоначально определены как операторы смены битов. Когда компилятор разбирает выражение, он в основном видит "операнд, оператор, операнд", а затем проверяет, являются ли операнды типов, к которым этот оператор может быть применен.
В этом случае у нас есть строковый литерал и (по-видимому) какое-то целое число, и компилятор знает, как выполнять математику на них (после преобразования строкового литерала в указатель).
Однако с точки зрения компилятора это не сильно отличается от чего-то вроде:
int a, b=1, c=2, d = 3;
a = b << c + d;
Разница заключается в том, что с операндами типа int
смысл довольно очевиден: он выполняет добавление и бит-сдвиг. С iostreams значение, связанное с <<
и >>
, изменяется, но синтаксис, разрешенный для них в выражении, не изменяется.
Из точки зрения компилятора единственный вопрос заключается в том, являются ли операнды для +
типов, для которых разрешен +
- в этом случае у вас есть pointer to char + integer
, поэтому это разрешено. Результатом является указатель на char, и он имеет перегрузку <<
, которая берет левый операнд типа ostream и правый оператор типа pointer to char
, поэтому выражение в целом отлично ( насколько это важно).
Ответ 4
"num"
Тип char const [4]
. Если numSamples
является целым числом, тип "num" + numSamples
имеет значение const char *
. Таким образом, вы вызываете operator <<
cor std::cout
, который перегружен для const char *
и печатает строку, которая начинается с адреса addres ( "num" ) + numSamples в арифметике указателя.
Попробуйте следующее:
cout << "num" + std::to_string(numSamples) << endl;
cout << "max" + std::to_string(maxSampleValue) << endl;
std::to_string()
вы можете найти в <string>
Ответ 5
если вы посмотрите operator_precedence, вы увидите, что +
оценивается до <<
, что оставляет это выражение оценивается перед передачей оператору <<
:
"num" + numSamples
Теперь "num"
будет static const char *
, и я предполагаю, что numSamples
является интегральным типом. Поскольку левая часть +
является типом указателя и вы добавляете к ней эту арифметику указателя. Теперь cout получает указатель на место в памяти, которое numSamples
или maxSamplueValue
больше, чем местоположение "num"
или "max"
. Скорее всего, все ваши статические строки были выстроены в один и тот же регион памяти, поэтому вы видели их, а не случайную бред.