изменчивая и двойная путаница - PullRequest
7 голосов
/ 02 октября 2010
int x = 2;
volatile int y = 2;

const int z = x/y;

int main(){
    int x = 2 + 3;

    double d = 7 / 3;
}

У меня есть три вопроса:

Во-первых, может ли компилятор вычислить значение 'z' во время компиляции, чтобы быть в этом случае равным 1?

Во-вторых, язаметил, что компилятор не генерирует инструкции по сборке для добавления 2 и 3 для инициализации x.Он непосредственно инициализирует x с 5. Можно ли сделать то же самое с 'd'?

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

Ответы [ 2 ]

4 голосов
/ 02 октября 2010

Во-первых, может ли компилятор вычислить значение 'z' во время компиляции, равное 1 в этом случае?

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

Во-вторых, я заметил, что компилятор не генерирует инструкции по сборке для добавления 2 и 3 для инициализации x,Он непосредственно инициализирует x с 5. Можно ли сделать то же самое с 'd'?

Да.Пока компилятор может доказать, что побочных эффектов нет.Например, если во время вычисления происходит переполнение или деление на ноль, он не может вычислить его во время компиляции, так как вычисление должно вызвать исключение CPU во время выполнения.

В-третьих, есть ли хорошая книга длячитать по этим двум понятиям?

Да.Стандарт C ++ ISO описывает именно то, что вы спрашиваете.Книги хороши для изучения основ или теории.Нет смысла писать книги, которые перефразируют все технические детали, описанные в стандарте.

1 голос
/ 02 октября 2010

Что касается "first" - y должен быть доступен при инициализации z, но я не думаю, что результат этого доступа должен использоваться для вычисления z, , если реализация почему-то знает, что она должна быть 2. Для этой программы (я думаю) есть только 2 способа, которыми она может иметь любое другое значение:

  1. это модифицируется отладчиком или другим вмешательством в программу.
  2. загрузчик помещает изменчивые глобальные переменные в некоторую область памяти, которая не работает как обычная память на вашем оборудовании. (в этом случае это было бы очень странное поведение, определяемое реализацией, до такой степени, что я не думаю, что это законно для написанного кода, но важно, если программа или какая-то часть процесса сборки вне программы может каким-то образом контролировать, где заканчивается объект).

Обе эти вещи могут быть исключены реализацией - во втором случае, зная, как ведет себя загрузчик, во-первых, устанавливая ограничения на то, что вы можете надеяться достичь с помощью отладчика («запись изменяемых переменных приводит к удивительное поведение "). Разочаровывает пользователя отладчика, но стандарт не ограничивает работу отладчиков или то, что «фактически» содержится в памяти, он просто ограничивает то, что делают допустимые реализации и программы C ++ и что «видит» C ++.

На практике вы могли бы подумать, что компилятор не потрудится рассматривать изменчивый объект как подлежащий оптимизации. Это неконстантный объект, и вы должны подозревать, что единственная причина для определения неконстантного изменчивого объекта заключается в том, что он будет меняться так, как компилятор не ожидает [*]. Вы бы надеялись, что он просто прочитает y и выполнит деление, но я считаю, что дело может быть сделано для оптимизации законным.

Что касается «второго» - в случае вашей программы компилятор может инициализировать d с предварительно вычисленным значением по правилу «как если», при условии, что он знает, что производит деление значения. По этому вопросу в вашей программе он может удалить d полностью.

«При условии, что он знает, что производит деление значений», зависит от реализации - если он поддерживает изменения режимов округления IEEE или эквивалентных, и если он не знает, какой режим должен быть в силе, то в общем случае он не знает заранее результат даже простой арифметики.

Правило "как будто" покрывает, скажем, 85% оптимизаций компилятора. Это описано в разделе 1.9 стандарта, который стоит посмотреть. Я согласен, что документ в целом довольно пугающий, и язык, который он использует, иногда непроницаем, но вам нужно с чего-то начинать, поэтому начните с того, что вам сейчас интересно; -)

[*] В частности, и это никак не рассматривается в стандарте C ++ 03, некоторые компиляторы (Microsoft) используют volatile в своем определении семантики потоков.

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