2017-02-20 4 views
13

У меня проблема - со следующим кодом я пытаюсь выяснить, что хранится на определенном адресе и как долго моя статическая переменная хранится в этой конкретной позиции. (Я читал, что статические переменные хранятся бесконечно и были весьма удивлены - хотели проверить, было ли это правдой). Код определяет статическую переменную (ее адрес в моей системе равен 0x1000020c0. Вероятно, это случайный случай, но он был постоянным)Адрес переменной необходимо загрузить в память?

Если я сейчас хочу узнать, какое целочисленное значение хранится по этому адресу, я должен сначала распечатайте адрес с помощью $ number, который затем дает 0x1000020c0. Повторное или повторное толкование адреса (0x1000020c0) дает только 100! если адрес был напечатан до или если я использую номер & при повторной интерпретации/переработке.

Может кто-нибудь объяснить, почему это так?

int static number = 100; 

// std::cout << number << std::endl; <- prints 100 

// prints 100 and the address 0x1000020c0 in my case 
// std::cout << number << " " << &number << std::endl; 

// this does not work unless &number is printed previously 
// std::cout << "Value is : " << *reinterpret_cast<int*>(0x1000020c0) << std::endl; 

// this does work and show the correct value (100) 
std::cout << "Value is : " << *reinterpret_cast<int*>(&number) << std::endl; 
+0

Поскольку, скорее всего, переменная не находится в этом адресе памяти, когда код отличается. –

+5

«хранится бесконечно» означает только время жизни программы, а не буквально до конца времени. – pjc50

+2

Ознакомьтесь с [правилом as-if] (http://stackoverflow.com/questions/15718262/what-exactly-is-the-as-if-ru). У вас есть наивная необоснованная ментальная модель для C++ и необоснованных убеждений о том, что делают C++-программы и конкретные операторы. Руководство по языку/библиотеке/справочник/спецификация сообщает вам, что вы можете ожидать, когда запускается программа; вы не имеете права ничего ожидать. – philipxy

ответ

20

В любой заданной программе объект может быть или не может быть сохранен в адресе 0x1000020c0. Нет никаких гарантий в любом случае. Адрес объекта определяется при компиляции (или, возможно, по ссылке) времени. Изменение программы может изменить адрес.

Если вы никогда не берете адрес локального статического объекта и не изменяете его, компилятор может оптимизировать переменную, чтобы память не использовалась. Если объект вообще не существует, то он определенно не существует в ячейке памяти 0x1000020c0.

Если вы используете объект таким образом, чтобы объект существовал, он будет находиться в некоторой ячейке памяти. Принятие адреса объекта обычно вызывает такое требование. Это поразительно похоже на observer effect в физике.

Если вы разыскиваете указатель, который не указывает на объект (соответствующего типа), поведение не определено.


при печати переделка/переосмысливать значение, которое в 0x1000020c0 он ничего не печатает

Как я уже объяснял выше, объект не гарантируется существование в ячейки памяти 0x1000020c0.

, хотя объект использовался, так как я напечатал его значение через std :: cout < < номер;

Доступ к значению объекта необязательно требует, чтобы объект существовал. Компилятор может доказать, что значение объекта равно 100, поэтому оно может сохранять это значение как константу, а не хранить статический объект вообще.

Кроме того, даже если статический объект действительно существует, он не обязательно будет существовать в адресе 0x1000020c0, если вы не возьмете адрес и не заметите его.


Как следствие: Никогда не приводите произвольное число к указателю (если не работать на некоторых встраиваемых платформ, которые HARDCODED отображения памяти). Увидев, что адрес объекта в одной программе равен 0x1000020c0, не делает 0x1000020c0 не произвольным в другой программе.

+0

Итак, пожалуйста, объясните, почему, когда я печатаю только номер, он все еще не работает - адрес, который находится под & number, по-прежнему пуст ... –

+0

@MaikR что вы подразумеваете под «адресом по-прежнему пустым»? – user2079303

+0

Когда я печатаю recast/reinterpret значение, которое находится на 0x1000020c0, оно ничего не печатает - даже если объект использовался, так как я напечатал его значение через std :: cout << number; –

2
  1. Предполагая, что конкретный адрес числа не лучшая идея.
  2. В C++ static внутри тела функции создается при первом вызове или когда первый раз программа C++ встречает переменную. Они никогда не создаются, если не используются.
  3. Если возможно, компилятор может выбрать оптимизацию static и заменить его на значение.
+0

Итак, пожалуйста, объясните, почему, когда я печатаю только номер, он все еще не работает - адрес, который находится под & number, по-прежнему пуст ... –

+1

@MaikR Поскольку компилятор может полностью оптимизировать эту переменную и использовать '100' для печати номера. Для этого вы можете использовать 'g ++ -O2 -fdump-tree-optimized'. Вывод, который я получил, это '_4 = std :: basic_ostream :: operator << (& cout, 100); [...] std :: __ ostream_insert > (& cout," Value is: ", 12); ' –

+0

Самое последнее предложение вводит в заблуждение, потому что' static' является перегруженным термином. Вы описываете функцию-область 'statics', но статика в глобальной области существует вне потока программы и не создается при первом использовании. – MSalters

0

Здесь отсутствует одно очень важное заявление - платформа, на которой вы запускаете этот код.

Статическая переменная не хранится «бесконечно»; он сохраняется в этом месте на время выполнения программы. Если вы работаете на встроенной платформе, где ваш код перескакивает на main() при включении питания, у вас нет ничего другого, что может мешать. Если вы работаете на любой другой платформе (Windows, Linux или любой другой), это место становится бесплатным, когда программа завершается, и сразу же доступна для чего-либо еще.

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

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

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

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

+0

Распределение памяти в другом процессе не должно влиять на полученный адрес, поскольку они в совершенно отдельном адресном пространстве в большинстве систем. – user1937198

+0

@ user1937198 Вы неправильно поняли, что я написал. Распределение памяти в другом процессе не повлияет на вашу программу во время ее запуска. Но любые выделения памяти по другому коду между вашей программой, заканчивающиеся и выполняемые во второй раз, или другие программы, останавливающиеся и запускающие, * будут * влиять на то, где код и данные вашей программы живут в памяти. Если «большинством систем» вы подразумеваете Linux и ПК, на самом деле они не являются действительно отдельными адресными пространствами, потому что все работает из ОЗУ. – Graham

+0

Эй, Грэхем, благодарю вас за ответ, но я думаю, что вы ошиблись. Я понимаю, что статические переменные существуют только для времени выполнения программы, однако была эта книга, в которой говорилось, что существует бесконечно, и я хотел проверить, был ли я прав, и они были неправы. Поэтому я использовал вышеприведенную конструкцию для определения адреса переменной, и когда она была одинаковой для 5 запусков, я предположил, что пока это будет адрес, на который я мог бы найти свое значение. Однако я был удивлен и не знал о оптимизации компилятора, поэтому сегодня я чему-то научился - это был хороший день. –

Смежные вопросы