Подтвердить что ты не робот

Почему можно назначить const char * для char *?

Я знаю, что, например, "hello" имеет тип const char*. Поэтому мои вопросы:

  • Как мы можем назначить литеральную строку типа "hello" для не const char* следующим образом:

    char* s = "hello";  // "hello" is type of const char* and s is char*
                        // and we know that conversion from const char* to
                        // char* is invalid
    
  • Литеральная строка, такая как "hello", которая будет иметь память во всей моей программе, или это как временная переменная, которая будет уничтожена при завершении оператора?

4b9b3361

Ответ 1

Фактически, "hello" имеет тип char const[6].

Но суть вопроса по-прежнему правильная: почему С++ позволяет нам назначить ячейку памяти только для чтения типам < const?

Единственная причина для этого - обратная совместимость со старым кодом C, который не знал const. Если бы С++ был строгим здесь, это нарушило бы много существующего кода.

Тем не менее, большинство компиляторов могут быть настроены так, чтобы предупреждать о таком коде как устаревшем или даже делать это по умолчанию. Кроме того, С++ 11 вообще запрещает это, но компиляторы еще не могут его выполнить.


Для поклонников Standerdese:
[Ref 1] С++ 03 Стандарт: §4.2/2

Строковый литерал (2.13.4), который не является широким строковым литералом, может быть преобразован в rvalue типа "указатель на char"; широкий строковый литерал может быть преобразован в rvalue типа "указатель на wchar_t". В любом случае результатом является указатель на первый элемент массива. Это преобразование рассматривается только тогда, когда существует явный соответствующий целевой тип указателя, а не когда требуется общая конвертация из lvalue в rvalue. [ Примечание. Это преобразование устарело. См. Приложение D.] Для целей ранжирования в разрешении перегрузки (13.3.3.1.1) это преобразование считается преобразованием от массива к указателю с последующим квалификационным преобразованием (4.4). [Пример: "abc" преобразуется в "указатель на const char" как преобразование от массива к указателю, а затем к "указателю на char" в качестве преобразования квалификации. ]

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

[Ref 2] C99 standard 6.4.5/5 "Строковые литералы - семантика":

В фазу 7 перевода байта или код нулевого значения добавляется к каждой многобайтовой последовательности символов, которая получается из строкового литерала или литералов. Последовательность многобайтовых символов затем используется для инициализации массива статической продолжительности хранения и длины, достаточной для того, чтобы содержать последовательность. Для символьных строковых литералов элементы массива имеют тип char и инициализируются отдельными байтами многобайтовой последовательности символов; для широких строковых литералов элементы массива имеют тип wchar_t и инициализируются с помощью последовательности широких символов...

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

Ответ 2

- это буквальная строка, подобная "hello", и память во всей моей программе будет полностью похожа на временную переменную, которая будет уничтожена при завершении оператора.

Он хранится в программных данных, поэтому он доступен в течение всей жизни программы. Вы можете вернуть указатели и ссылки на эти данные из текущей области.

Единственная причина, по которой const char* отбрасывается на char*, является comatiblity с c, как системные вызовы winapi. И этот актер сделан неявным, в отличие от любого другого каста Const.

Ответ 3

Просто используйте string:

std::string s("hello");

Это будет С++. Если вы действительно должны использовать char, вам нужно создать массив и скопировать содержимое поверх него.

Ответ 4

Ответ на ваш второй вопрос заключается в том, что переменная s хранится в ОЗУ как тип pointer-to-char. Если он глобальный или статический, он выделяется в куче и остается там на всю жизнь запущенной программы. Если это локальная ( "авто" ) переменная, она выделяется в стеке и остается там до тех пор, пока не вернется текущая функция. В любом случае он занимает объем памяти, необходимый для хранения указателя.

Строка "Hello" является константой и хранится как часть самой программы вместе со всеми другими константами и инициализаторами. Если вы построили свою программу для работы на устройстве, строка будет сохранена в ПЗУ.

Обратите внимание, что поскольку строка является постоянной и s является указателем, копирование не требуется. Указатель s просто указывает на то, где хранится строка.

Ответ 5

В вашем примере вы не назначаете, а строите. std::string, например, имеет конструктор std::string(const char *) (на самом деле он более сложный, но это не имеет значения). И, аналогично, char * (если это был тип, а не указатель на тип), может иметь конструктор const char *, который копирует память.

Я действительно не знаю, как компилятор действительно работает здесь, но я думаю, что он может быть похож на то, что я описал выше: копия "Hello" построена в стеке, а s инициализируется этой копией адрес.