что происходит с данными, объявленными как const в c

#c

#c

Вопрос:

Когда мы объявляем const переменную, в книге Брюса Экеля говорится, что происходит свертывание константы, что означает, что память не выделяется для переменной.

Что происходит, когда мы объявляем переменную как const ?

  1. Как компилятор может свободно оптимизировать const переменные?
  2. Всегда ли выделяется память для const переменных, и при каких обстоятельствах это может быть не так?

Комментарии:

1. Вам нужно быть более точным в том, что вы хотите знать.

2. Я хотел узнать, что такое сворачивание памяти и почему сворачивание памяти выполняется для переменной const .

3. Похоже, что «сворачивание памяти» — это термин, изобретенный Экелем (если OP цитирует правильно) — google для этого не показывает ничего соответствующего.

Ответ №1:

Компилятор волен оптимизировать переменные const (и все остальное) до тех пор, пока вы не сможете отличить их от того, что делает программа.

Например:

 const int three = 3;
const int four = 4;

int f() { return three * four; }
  

Здесь компилятор может не выделять память для переменных и, вероятно, выдаст точно такой же код, как если бы он был написан return 12;

Но если бы вы взяли адрес three , или привязали к нему ссылку, или объявили его как extern , то компилятор, вероятно, был бы вынужден выделить для него память.

Комментарии:

1. Я согласен с тобой, Алан, но где сохраняется значение для трех и четырех. Вы имеете в виду, что они хранятся в таблице символов?

2. Они могут не храниться в двоичном файле, если они не нужны во время выполнения — например, если они помечены как file static и используются только в выражениях, подобных приведенному выше. Даже если они необходимы во время выполнения, они могут храниться непосредственно в инструкциях процессора, а не в разделе .DATA.

3. Компилятору необходимо знать значения, так что да, к ним каким-то образом придется обращаться через таблицу символов. Во время выполнения нет необходимости сохранять значения.

4. @gnud нет необходимости делать их явно статическими, переменные const по умолчанию имеют внутреннюю связь.

Ответ №2:

Я нашел следующую цитату в PDF-файле, приписываемом Брюсу Экелю:

const int bufsize = 100; Вы можете использовать bufsize в любом месте, где компилятор должен знать значение во время компиляции. Компилятор может использовать bufsize для выполнения свертки констант, что означает, что компилятор уменьшит сложное постоянное выражение до простого, выполнив необходимые вычисления во время компиляции. Это особенно важно в определениях массивов:

Предполагая, что вы имели в виду «постоянное сворачивание», а не «сворачивание памяти», он имеет в виду следующее:

 const int i = 10;
const int j = 20;
int k = i   j;
  

Память не обязательно выделять для i и j , если компилятор может доказать, что это единственный раз, когда они используются. В этом случае он может заменить все три строки на int k = 30; Поскольку переменные были помечены const , компилятор волен предположить, что их значения никогда не изменятся, и он достаточно умен, чтобы выполнить добавление за вас заранее, а не ждать времени выполнения.

Как бы то ни было, я бы не стал слишком беспокоиться об этом, если вы все еще изучаете язык. Это деталь реализации; обычно вы можете рассчитывать на то, что это произойдет, но конечный результат в любом случае одинаков. Пишите код, который имеет смысл, используйте const по мере необходимости для предотвращения ошибок [не как средство экономии памяти], и если компилятор способен выдать что-то особенное для вас, тем лучше.

———— Далее следует оригинальный ответ, поскольку это своего рода смежная тема

Без прямой цитаты, я предполагаю, что он имеет в виду что-то вроде этого:

 //in file 1:
const char* string1 = "Hello world!";
//in file 2:
const char* string2 = "Hello world!";
//in file 3:
const char* string3 = "world!";
  

При некоторых обстоятельствах компилятор / компоновщик может определить это, string1 и string2 оба указывают на одну и ту же строку. Таким образом, ему не нужно создавать два отдельных строковых объекта, которые содержат одни и те же данные, и assert(string1 == string2) в конечном итоге все будет выполнено успешно. Еще более интеллектуальная настройка могла бы заметить, что string3 это подстрока первых двух, и в итоге вы получите assert(string3 == string1 6) . В фактических данных исполняемого файла вы получаете одну строку, хотя в коде их три.

В C на самом деле не имеет значения, являются ли они константами const , потому что вы не можете присвоить строковому литералу неконстантное значение char* . Но в целом, эта замена была бы недействительной, если бы любой из трех строк было разрешено изменять память, на которую они указывают. Пользователь, вероятно, не намерен *string1 = '5' меняться *string2 , поэтому в этом случае три строки не могут быть сжаты.

Комментарии:

1. Исправьте, Деннис, его постоянное сворачивание, поскольку вы сказали «Память не обязательно выделять для i и j, если «, то где будет сохранено значение. Как вы думаете, эти значения хранятся в таблице символов. поскольку каждая единица компиляции обладает таблицей символов. Я не уверен, хотя

2. @Chris: Они получили бы записи в таблице символов во время компиляции, да, просто помеченные как константы. После компиляции в подобном случае они, скорее всего, просто исчезают, а значение 50 появляется непосредственно внутри инструкций. В других случаях новое значение будет вставлено вместе с любыми другими данными, сохраненными исполняемым файлом.

Ответ №3:

» означает, что память не выделена для переменной .. «

Вы ошибаетесь. Если это переменная (будь то const или non const), она должна находиться в некоторой части памяти.

Когда вы объявляете переменную как const means, переменная не может быть изменена в течение срока ее службы.

 const int num = 10 ;

num = 20 ; // Error : num cannot be modified. It is just a read only variable.

int var = 10 ;
var = 20 ;  // var is a modifiable integer variable.
  

Комментарии:

1. Для области видимости функции или статических переменных const файла компилятор при компиляции CU знает, был ли когда-либо взят адрес переменной или использовалось только ее значение. Если его адрес никогда не используется, то это может заменить использование переменной const значением переменной; по крайней мере, для простых типов.

2. @Simone, вы можете безопасно приводить const только к тому, что изначально не было const . Компилятор может свободно размещать переменные const в памяти, доступной только для чтения.

3. @Simone: Это вызывает неопределенное поведение, хотя.

4. Неполный ответ, есть функции-члены const и тонкости указателей и const . Затем есть const_cast и ключевое слово mutable. И что означает ‘const volatile’?

5. @Skizz- Ну, в OP упоминалось о const переменных. Я просто пытался дать представление.