Где и как хранятся константы?
Мне было интересно, как сохраняются константы, как целые, так и строковые литералы. Мое понимание строковых литералов заключается в том, что они создаются в глобальной статической памяти при запуске программы и сохраняются до выхода программы. В случае «abcde» , хотя я не дал ему имя переменной, я могу принять его адрес ( chPtr ), и я предполагаю, что я мог бы, вероятно, разыменовать chPtr в любое время до завершения программы, и значения символов все равно будут там, даже если я разыменовал его вне области, где он был объявлен. Является ли переменная const int «five» также помещена в глобальную статику и что адрес p2 также может ссылаться в любое время?
Почему я могу взять адрес «five» , но я не могу запросить: &(5) ? Сохранены ли константы «5» и «five» по-разному? и где «5» сохраняется в памяти?
3 ответа
Вы не можете взять адрес литерала (например, &(5) ), потому что литерал не «хранится» нигде — он фактически написан в инструкции сборки. В зависимости от платформы вы получите разные инструкции, но пример добавления MIPS64 будет выглядеть следующим образом:
Попытка взять адрес немедленного значения бессмысленна, поскольку он не находится в (данных) памяти, но на самом деле является частью инструкции.
Если вы объявляете const int i = 5 и не нуждаетесь в его адресе, компилятор может (и, вероятно, будет) преобразовывать его в литерал и размещать 5 в соответствующих инструкциях по сборке. Как только вы попытаетесь принять адрес i , компилятор увидит, что он больше не может этого сделать, и поместит его в память. Это не так, если вы просто пытаетесь взять адрес литерала, потому что вы не указали компилятору, что ему нужно выделить место для переменной (когда вы объявляете const int i , он выделяет пространство в первом pass, и позже определит, что он больше не нужен — он не работает в обратном порядке).
Строковые константы хранятся в статической части памяти данных — вот почему вы можете взять их адрес.
«Это зависит», вероятно, не удовлетворительный ответ, но он правильный. Компилятор сохранит некоторые константные переменные в стеке, если это необходимо (например, если вы когда-либо берете его адрес). Однако в компиляторах всегда существовала идея переменной «constexpr», даже если мы не всегда связывали ее с mechansim: если выражение можно вычислить во время компиляции, то вместо того, чтобы вычислять его во время выполнения, мы можем вычислить его время компиляции. И если мы можем вычислить его во время компиляции, и мы никогда не делаем ничего, что требует от него чего-то другого, тогда мы можем удалить все это вместе и превратить его в литерал, который будет частью инструкции!
Возьмем, к примеру, следующий код:
Посмотрите, насколько умным является компилятор:
(volatile сообщает компилятору, что он не делает причудливые трюки памяти этой переменной). В строке 41, когда я использую c , добавление выполняется с помощью LITERAL 0x5, несмотря на то, что оно даже является комбинацией другого кода. Строки 37-39 не содержат инструкций.
Теперь измените код так, чтобы мне понадобилось местоположение:
Итак, мы видим, что a инициализируется в фактическое пространство памяти, в стеке (я могу сказать cz rsp). Но подождите. c зависит от a, но всякий раз, когда я использую c, он все еще является буквальным 5! Что здесь происходит? Ну, компилятор знает, что он должен находиться в ячейке памяти из-за того, как он используется. Однако он знает, что значение переменной никогда не является NOT 2, поэтому всякий раз, когда я использую его способами, которым не нужна память, я могу использовать его как литерал 2. Это означает, что строка a в строке 37 не такая, как a в строке 43.
Итак, где хранятся константные переменные? Они хранятся там, где им НЕОБХОДИМО хранить. CRAZY.
(btw, все они были скомпилированы с g++ -g -O2, разные компиляторы/флаги будут оптимизировать его по-другому, это в основном демонстрирует, что может сделать компилятор, единственная гарантия заключается в том, что ваш код будет вести себя правильно.)
Где хранятся строковые константы в памяти?
В программе на C++, где хранятся постоянные данные, особенно строковые константы?
Я спрашиваю, потому что в следующем вопросе:
Ответ Дэймона, имеет следующее в конце:
String_view, в отличие от строки, не выделяет непостоянную память, копирует в нее постоянные данные, а затем делает вид, что это константа. Вместо этого он будет управлять указателем непосредственно на постоянные данные, и все.
Таким образом, ваши константы действительно (а не только формально) постоянны, нет выделения, нет возможности исключений и двойного использования памяти. И по большей части это все еще выглядит и пахнет как строка. Единственное заметное отличие состоит в том, что string_view не гарантирует нулевое завершение (но символьная константа, на которую он указывает, так что это не имеет значения), и тот факт, что это действительно константа, не изменяемая. это именно то, что вам нужно,
Не даже константы должны быть сохранены в памяти где-нибудь? И если они хранятся в памяти (так как память конечна), разве не возможно, что может быть выдано исключение, потому что больше нет памяти?
2 ответа
Проблема в том, что std::string это объект, а не просто данные.
Это означает, что когда вы объявляете
статические данные, которые зарезервированы в двоичном файле, являются теми для литерала «foobar» (предназначен как const char* ) и место, необходимое для хранения std::string объект, который НЕ является пространством, необходимым для хранения его содержимого.
Представь себе std::string как то скажем
Это тривиальный небезопасный фрагмент кода, но он просто дает вам идею. Когда у вас есть static std::string единственное необходимое пространство sizeof(char*)+sizeof(size_t) байты, так как сами данные динамически размещаются в куче.
Вот почему с помощью static const std::string тратит вдвое больше места: для самого литерала, который передается конструктору строки, и для std::string ,
Теперь этот объект не является «предварительно созданным» во время компиляции. Он построен во время выполнения, и стандарт не гарантирует, когда это произойдет точно (действительно, если это произойдет до вызова main вы не можете поймать любое исключение, которое может вызвать конструктор).
Цитируемый string_view это обертка вокруг const char* который не тратит впустую память, поскольку он хранит только указатель на содержимое, что не относится к обычному std::string который предназначен для изменчивости.
Вопрпос про const: в какой области памяти они находятся, и где это объявлять ?
Что это за фишка языка? s+=i[a]; почему это вообще работает? Где про это прочитать?
#include <iostream> using namespace std; int main() < int a=<1,2,3,4,5>; int s=0; .
Как на форме в делфи разместить эти компоненты, где они находятся?
TForm1 = class(TForm) MyForm: TImage; Pole: TImage; Close1: TImage; Label1.
Архивировать при помощи WinRAR файлы в ту же папку, где они находятся
Подскажите пожалуйста. Как создать bat который архивировал файлы в туже папку где они находятся.
Составить программу и схема-блок для четырех точек и определить в какой четверти они находятся
Задача такова — нужно составить программу и схема-блок для четырех точек и определить в какой.
Как константа хранится в памяти в C?
Работая над созданием своего собственного языка программирования, который в частности поддерживает указатели и константы, мне интересно, как константы хранятся в памяти в таких языках, как C? Я прочитал в StackOverflow, что они хранятся в памяти только для чтения во время выполнения, но я не понимаю, как это возможно, поскольку следующий код хорошо компилируется и выполняется:
Здесь я определяю константу с именем x и создаю из нее указатель, чтобы я мог изменить ее значение. Это означает, что x нельзя хранить в постоянной памяти.
Итак, мне действительно интересно, как константы хранятся во время выполнения?
4 ответа
Обычно, особенно когда оптимизация включена, компилятор пытается сделать константы максимально эффективными. Например, если вы напишите x = 3*4 + 5 , компилятор уменьшит это значение до 17 во время компиляции, а не поместит 3, 4 и 5 в скомпилированную программу.
Небольшие константы, которые используются напрямую, часто кодируются в непосредственные поля инструкций.
Если компилятор не может поместить константу в непосредственное поле инструкции, он обычно будет стремиться сохранить ее в постоянной памяти.
Однако приведенный вами пример усложняет компилятор. Код в вашем примере:
- Определяет const объект внутри подпрограммы (в отличие от области видимости файла).
- Берет адрес объекта.
Если вы просто определили объект const и не получили его адрес, компилятор может сохранить константу в разделе данных только для чтения.
Однако, поскольку вы берете адрес объекта, возникает проблема. Рутины можно вызывать рекурсивно. (Ваша программа не вызывает main рекурсивно, но компилятор предназначен для поддержки рекурсивных вызовов, поэтому обсуждаемые здесь проблемы относятся к ее дизайну.) Когда процедура вызывается рекурсивно, новые экземпляры объектов, определенных в ней, должны быть создан (в модели вычислений C). Если адрес объекта const не был взят, компилятор мог бы оптимизировать его, используя одну и ту же постоянную память для всех экземпляров объекта — поскольку их значения никогда не меняются, никто не может сказать, что они были только одним экземпляром. нескольких копий.
Однако разные экземпляры объекта можно отличить по их адресам. Так как вы берете адрес объекта, компилятор хочет создать различные его экземпляры. Это трудно сделать в постоянной памяти. Программы обычно не поддерживают стек для памяти только для чтения, поэтому у компилятора нет удобного способа отслеживать несколько экземпляров, которые должны быть созданы для объектов в памяти только для чтения. (Было бы трудно поддерживать стек для доступной только для чтения памяти. Если то, что находится в стеке, может отличаться в разное время, то память для этого стека должна измениться. Таким образом, даже если на стек, сам стек не может быть доступен только для чтения.)
Таким образом, в этом случае компилятор помещает ваш const объект в обычный стек.
Конечно, это не то поведение, на которое вы можете положиться. Попытка изменить значение определенного объекта const имеет поведение, не определенное стандартом C. Несмотря на то, что в этом случае он работает, возможно, что в более сложных программах компилятор может преобразовать вашу программу с различными оптимизациями, в результате чего ваша программа потерпит неудачу при попытке изменить объект const нравится. Например, printf(«%d», *y) может вывести «2», поскольку память, на которую указывает y , была изменена на 2, тогда как printf(«%d», x) может вывести «1», поскольку x известен (в C модель вычисления), чтобы быть константой 1.
AFAIK, как они хранятся, это детали реализации в зависимости от компилятора. Тем не менее, он обычно хранится в текстовом разделе.
Кстати, const просто применяет вас, чтобы компилятор предупреждал вас, если переменную const нужно изменить.
