Хранение переменных в памяти, C ++ - PullRequest
3 голосов
/ 02 апреля 2010

Сегодня что-то странное пришло мне в голову. Когда я хочу сохранить некоторую строку в C (C ++) по-старому, без использования заголовка строки, я просто создаю массив и сохраняю эту строку в нем. Но я прочитал, что любое определение переменной в C в локальной области функций в конечном итоге помещает эти значения в стек.

Итак, строка на самом деле на 2 * больше, чем нужно. Потому что сначала инструкции push помещаются в память, но затем, когда они выполняются (помещаются в стек), создается другая «копия» строки. Сначала инструкции push, затем пространство стека используется для одной строки.

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

Спасибо.

Ответы [ 4 ]

5 голосов
/ 02 апреля 2010

Существует несколько способов работы со статическими строками в C и C ++:

char string[] = "Contents of the string";
char const *string2 = "Contents of another string";

Если вы делаете это внутри функции, первая создает строку в стеке, как вы описали. Второй просто создает указатель на статическую строку, встроенную в исполняемый файл, примерно так, как вы и предполагали.

1 голос
/ 02 апреля 2010

Это не так, как это работает. Ничто не «выталкивается», компилятор просто резервирует место в кадре стека. Вы не можете вернуть такую ​​строку из функции, вы вернете указатель на кадр мертвого стека. Любой последующий вызов функции уничтожит строку.

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

1 голос
/ 02 апреля 2010

Очень хороший вопрос. Вы знаете, что использование ключевого слова static для переменной (определение) EDIT: объявление делает то, что вы описали, верно?

Что касается местных жителей, то оптимизация производительности является ключевым фактором. Локальная переменная не может быть доступна вне области функции. Почему тогда компилятор пытается сохранить память для него вне стека?

0 голосов
/ 04 апреля 2010

Если у вас есть:

extern void some_function(char * s, int l);

void do_it(void) {
     char str[] = "I'm doing it!";
     some_function(str, sizeof(str) );
}

Это может превратиться в нечто вроде (в псевдо-ассм для обработанного процессора):

.data
local .do_it.str       ; The contents of str are stored in a static variable
.text   ; text is where code lives within the executable or object file
do_it:
    subtract (sizeof(str)) from stack_pointer        ; This reserves the space for str, sizeof(str)
                                                     ; and a pointer to str on the stack

    copy (sizeof(str)) bytes from .do_it.str to [stack_pointer+0]   ; this loads the local variable
                                               ; using to the memory at the top of the stack
                                               ; This copy can be a function call or inline code.

    push sizeof(str)         ; push second argument first
    push stack_pointer+4     ; assuming that we have 4 byte integers,
                             ; this is the memory just on the other side of where we pushed
                             ; sizeof(str), which is where str[0] ended up

    call some_function

    add (sizeof(str)+8) to stack_pointer          ; reclaim the memory used by str, sizeof(str),
                                                  ; and the pointer to str from the stack
    return

Из этого вы можете видеть, что ваше предположение о том, как создается локальная переменная str, не совсем верно, но это не всегда так эффективно, как могло бы быть.

Если вы сделали

void do_it(void) {
     static str[] = "I'm doing it!";

Тогда компилятор не зарезервирует место в стеке для строки, а затем скопирует ее в стек. Если some_function изменяет содержимое str, то следующий (или одновременный) вызов do_it (в том же процессе) будет использовать измененную версию str.

Если some_function был объявлен как:

extern void some_function(const char * s, int l);

Тогда, так как компилятор может видеть, что нет никаких операций, которые изменяют str в пределах do_it, он также может обойтись без создания локальной копии str в стеке, даже если str не была объявлена ​​static.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...