Строки в экземплярах статической памяти подсчитываются

Как я знаю, C-подобные строки compiletime хранятся в статической памяти как только один экземпляр. Например, я получил как true пример gcc 4.6, приведенный ниже. Но я думаю, что это всегда так, и может быть переносимым. Поведение на C и С++ интересно.

#include <iostream>

bool amIportable(const char* value) {
  const char* slocal = "Hello";
  return (slocal==value);
}

int main() {
  const char* s = "Hello";
  std::cout << std::boolalpha 
            << amIportable(s) << '\n'
            << amIportable("Hello") << '\n';
}

Ответ 1

Нет, это не всегда так, и не переносимо.

Объединение идентичных строковых литералов - это оптимизация, которая выполняется компилятором и компоновщиком, работающим вместе. Последние версии как GCC, так и Microsoft компилятора поддерживают его, но только когда установлены определенные переключатели оптимизации.

И это не просто функция "on" или "off". Различные компиляторы и различные параметры оптимизации также влияют на то, насколько агрессивно это выполняется. Например, иногда строковые литералы объединяются только в рамках отдельной функции, в других случаях это происходит на уровне единицы перевода, а также в других случаях, когда линкер может взаимодействовать с ним через несколько единиц перевода.

Это разрешено, потому что стандарты C и С++ оставляют это поведение зависимым от реализации.

Ответ 2

Нет, это зависит от реализации как для C, так и для С++.

C11 §6.4.5/7 Строковые литералы

Не указано, являются ли эти массивы различными, если их элементы имеют соответствующие значения. Если программа пытается изменить такой массив, поведение undefined.

С++ 11 §2.14.5/12 Строковые литералы

Определены ли все строковые литералы (то есть, хранятся в объектах с неперекрывающимися объектами). Эффект попытки изменить строковый литерал - undefined.

Ответ 3

Но интересно, всегда ли это верно.

Нет, по крайней мере, в стандарте C сказано что-то вроде "не совпадают ли два идентичных строковых литерала в одном массиве".

Ответ 4

Вы сравниваете два разных строковых литерала, которые случаются с имеют такое же значение. Согласно стандарту С++, это реализация определяет, занимают ли одинаковые строковые литералы или нет (что означает, что реализация должна документ, что он делает); в соответствии со стандартом C, это неопределенные. (Я полагаю, что стандарт С++ позволил бы реализация для документирования чего-то в строках строки литеры одинакового содержания имеют один и тот же экземпляр, если они находятся в одной и той же единице перевода и не имеют одинакового в противном случае.)

Если ваша цель состоит в том, чтобы иметь возможность просто сравнивать указатели, обычные решение заключается в использовании функции (статической, если она является членом класса) который возвращает строковый литерал:

char const*
value()
{
    return "Hello";
}

bool
isHello( char const* str )
{
    return str == valule;
}

а затем убедитесь, что все экземпляры строки получены вызов value().