Каков тип данных строкового литерала в С++?

Аналогичные вопросы заданы о типе данных строковых литералов в С++.

Многие люди процитировали стандарт:

Узкий строковый литерал имеет тип "массив из n const char", где n - размер строки, как определено ниже, и имеет статическую продолжительность хранения (3.7)

В основной функции я написал следующий оператор:

  char cstring[]= "hellohellohellohellohellohello";

Но я не могу найти ни строковый литерал, который хранится как статические данные в сборке. Фактически, сборка показывает, что строка разлагается и "сохраняется" непосредственно в инструкциях.

    movl    $1819043176, -48(%rbp)
    movl    $1818585199, -44(%rbp)
    movl    $1701343084, -40(%rbp)
    movl    $1752132716, -36(%rbp)
    movl    $1869376613, -32(%rbp)
    movl    $1819043176, -28(%rbp)
    movl    $1818585199, -24(%rbp)
    movw    $28524, -20(%rbp)
    movb    $0, -18(%rbp)

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

char cstring1[] = "hellohellohellohellohellohello";

Сборка

cstring1:
    .string "hellohellohellohellohellohello"

Приведенный выше пример доступен в Интернете здесь.

Таким образом, это не соответствует приведенному стандарту. Может быть, есть некоторые исключения из того, что здесь цитируется?

Ответы

Ответ 1

Выражения имеют тип. Строковые литералы имеют тип, если они используются как выражение. У вас нет.

Рассмотрим следующий код:

#include <stdio.h>

#define STR "HelloHelloHello"

char global[] = STR;

int main(void)
{
    char local[] = STR;
    puts(STR);
}

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

Первый, инициализатор для global, является частью статической инициализации объекта со статическим временем жизни. В разделе 3.6.2 статическая инициализация не должна выполняться во время выполнения; компилятор может организовать предварительный форматирование результата в двоичном изображении, чтобы процесс начал выполнение с уже существующими данными, и он сделал это здесь. Также было бы законно инициализировать этот объект так же, как local[], если он был выполнен до начала динамической инициализации глобальных символов.

Второй, инициализатор для local, является строковым литералом, но на самом деле это не выражение. Он обрабатывается по специальным правилам 8.5.2, который гласит, что символы внутри строкового литерала независимо используются для инициализации элементов массива; строковый литерал не используется как единица. Этот объект имеет динамическую инициализацию, что приводит к загрузке значения во время выполнения.

Третий, аргумент для вызова puts(), фактически использует строковый литерал как выражение, и он будет иметь тип const char[N], который распадается на const char* для вызова. Если вы действительно хотите изучить объектный код, используемый для обработки типа исполняемого файла строкового литерала, вы должны использовать литерал в выражении, как это делает этот вызов функции.

Ответ 2

Он соответствует стандарту в соответствии с правилом "как есть".

Поскольку единственное, что используется для строкового литерала, это инициализировать cstring, для него нет необходимости в каком-либо объектном представлении. Компилятор исключил его в пользу инициализации cstring альтернативным способом, который имеет эквивалентные результаты, но что компилятор решает лучше в некотором отношении (скорость или размер кода).

Ответ 3

Я думаю, что определение, которое вы цитируете, должно интерпретироваться как ссылка на строковые литералы, чье местоположение хранения явно не объявлено, например выражение формата в printf(). Для того, чтобы такой код работал, эти строковые литералы должны быть где-то сохранены; определение указывает, где они хранятся, если это невозможно сделать из контекста.

На стороне примечания: строковый литерал в вашем main() не отображается как статические данные, поскольку переменные, объявленные в функциях, по умолчанию являются "автоматическими". Если бы вы вместо этого записали static char cstring[]=..., вы бы увидели его там же, где cstring1[].

И еще одно: место хранения НЕ является частью типа данных!