C Длительность строк, констант, составных литералов и, почему нет, самого кода - PullRequest
1 голос
/ 28 февраля 2011

Я не помню, где я читал, что если я передаю строку в функцию вроде. char *string; string = func ("heyapple!"); char *func (char *string) { char *p p = string;</p> <p>return p; } printf ("%s\n", string);

Указатель строки по-прежнему действителен, потому что "heyapple!"находится в памяти, он находится в коде, который я написал, поэтому он никогда не будет взлетать, верно?

А насчет констант вроде 1, 2.10, 'a'?

и составных литералов?

как если я сделаю это: <pre>func (1, 'a', "string");

Только строка будет выполнять все мои программы, или константы тоже будут?

ДляНапример, я узнал, что могу взять адрес строки, делая это <pre>&"string";

Можно ли взять адрес литералов констант?как 1, 2.10, 'a'?

Я передаю тезисы аргументам функций, и он должен иметь статическую длительность, как строки без слова static.

Большое спасибо.

Ответы [ 4 ]

2 голосов
/ 28 февраля 2011

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

При char* hello = "hello"; происходит две вещи:

  • строка "hello" игде-то в памяти записан нулевой терминатор
  • переменная с именем hello содержит значение, являющееся адресом этой памяти

При int i = 0; происходит только одно:

  • переменная с именем i содержит значение 0

Когда вы передаете переменные в функции, их значения всегда копируются.Это называется передача по значению и отлично работает для примитивных типов, таких как int, double и т. Д. С указателями это сложно, потому что копируется только адрес;Вы должны убедиться, что содержимое этого адреса остается действительным.

Краткий ответ: да.1 и 'a' задерживаются из-за передачи по значению семантики, а "hello" задерживается из-за строкового литерала .

2 голосов
/ 28 февраля 2011

Это не имеет большого смысла.

Значения, которые не являются указателями, не могут быть «освобождены», они являются значениями, они не могут исчезнуть.

Если я это сделаю:

int c = 1;

Переменная 'c' не является указателем, она не может делать ничего, кроме как содержать целочисленное значение, если быть более точным, она НЕ может содержать целочисленное значение. Вот и все, альтернатив нет.

На практике литералы будут скомпилированы в сгенерированный машинный код, так что где-то в коде, полученном в результате выше, будет что-то вроде

load r0, 1

Или как выглядит ассемблер для базового набора команд. «1» является частью кодировки команд, она не может исчезнуть.

1 голос
/ 28 февраля 2011

Такие вещи, как 1, 'a' и "heyapple!" называются литералами , и они сохраняются в скомпилированном коде и в памяти, когда они должны использоваться. Если они остаются или не сохраняются в памяти на время действия программы, зависит от того, где они объявлены в программе, их размера и характеристик компилятора, но обычно можно предположить, что да, они хранятся где-то в память, и что они не уходят .

Обратите внимание, что, в зависимости от компилятора и ОС, может быть возможно изменить значение литералов, непреднамеренно или преднамеренно. Многие системы хранят литералы в областях только для чтения (разделы CONST) памяти, чтобы избежать неприятных и трудных для отладки аварий.

Для литералов, которые вписываются в слово памяти, например int s и char s, не имеет значения, как они хранятся: каждый повторяет литерал по всему коду и позволяет компилятору решить, как сделать его доступным. Для больших литералов, таких как строки и структуры, было бы плохой практикой повторять, поэтому ссылка должна быть сохранена.

Обратите внимание, что если вы используете макросы (#define HELLO "Hello!"), то компилятор сам решает, сколько копий литерала хранить, потому что расширение макросов - это точно, замена макросов на их расширение, которое происходит перед компилятором. снимает исходный код Если вы хотите убедиться, что существует только одна копия, вы должны написать что-то вроде:

#define HELLO "Hello!"
char* hello = HELLO;

Что эквивалентно:

char* hello = "Hello!";

Также обратите внимание, что объявление типа:

const char* hello = "Hello!";

Сохраняет hello неизменным, но не обязательно память, на которую он указывает, из-за:

char h = (char ) привет; h [3] = 'n';

Я не знаю, определен ли этот случай в ссылке на C, но я бы не стал на это полагаться:

char * hello = "Привет!"; char * hello2 = "Привет!"; // это та же самая память?

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

Если вы хотите изменить копию литерала, использовать массивы вместо указателей , поэтому гарантированно используется другая копия литерала (а не псевдонима) каждый раз:

char hello[] = "Hello!";

Возвращаясь к исходному вопросу, память для литерала "heyapple!" будет доступна (будет ссылочной), пока ссылка на нее хранится в работающем коде. Хранение целого модуля (загружаемой библиотеки) в памяти из-за литерала может иметь последствия для общего использования памяти, но это еще одна проблема (вы также можете вызвать выгрузку модуля, который определяет литерал и получить всевозможные странные результаты).

0 голосов
/ 28 мая 2012

Во-первых, it IS in the code the I wrote, so it never will be take off, right? мой ответ - да.Я рекомендую вам взглянуть на структуру ELF или структуру исполняемого файла.Позиция, в которой хранится строковый литерал, зависит от реализации, в gcc строковый литерал хранится в сегменте .rdata.Как следует из названия, .rdata только для чтения.В вашем коде

   char *p
   p = string;

указатель p теперь указывает на адрес в сегменте, доступном только для чтения, так что даже после завершения вызова функции этот адрес остается действительным.Но если вы попытаетесь вернуть указатель на локальную переменную, то это опасно и может привести к трудным для обнаружения ошибкам:

int *func () {
    int localVal = 100;
    int *ptr = localVal;
    return p;
}
int val = func ();
printf ("%d\n", val);

после выполнения func, поскольку пространство стека func извлекается средой выполнения c, адрес памяти, в котором хранился localVal, больше не гарантирует сохранение исходного значения localVal.Он может быть переопределен операцией после func.

Вернуться к названию вашего вопроса

-

  1. string literal иметь static duration.
  2. Что касается "А насчет констант типа 1, 2.10, 'a'?"мой ответ НЕТ, вы не можете получить адрес целочисленного литерала, используя &1.Вас может смущать название «целочисленная константа», но 1,2.10,'a' не является правильным значением!Они не идентифицируют место в памяти, поэтому у них нет длительности, переменная, содержащая их значение, может иметь длительность
  3. составных литералов, ну, я не уверен в этом.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...