Простейшим вариантом является, вероятно, объявление его как глобального без const
, поэтому компилятор не может предположить, что он все еще имеет значение статического инициализатора.
int K = 123456;
Даже оптимизация во время компоновки не может знать, что библиотечная функция не имеет доступа к этой глобальной функции, при условии, что вы вызываете ее в своей программе.
Если вы использовали static int K = 123456;
, компилятор мог заметить, что никакие функции в модуле компиляции не записывают значение, и ни одна из них не передает и не возвращает его адрес, поэтому экранирующий анализ для всего модуля компиляции может обнаружить, что это было постоянный и может быть оптимизирован.
(Если вы действительно хотите, чтобы это было static int K;
, включите глобальную функцию, такую как void setK(int x){K=x;}
, которую вы никогда не вызываете. Без Link-Time Optimization, компилятор должен будет предположить, что что-то вне этого модуля компиляции могло бы вызвать эта функция и была изменена K
, и любой вызов функции, определение которой не видно, может привести к такому вызову.)
Помните, что volatile const int K = 123456;
может значительно ухудшить оптимизацию, чем сделать ее не const
, особенно если у вас есть выражения, использующие K
несколько раз.
(Но любой из них может сильно повредить, в зависимости от того, какие оптимизации были возможны. Распространение констант может быть огромной победой.)
Компилятор должен выдавать asm, который загружает ровно K
один раз за каждый раз, когда C абстрактная машина читает его. (Например, чтение K
считается видимым побочным эффектом, например, чтение из порта MMIO или местоположения, на котором установлена аппаратная точка наблюдения.)
Если вы хотите, чтобы компилятор загружал его один раз за цикл, и предполагали, что K
является инвариантом цикла, то код, который его использует, должен выполнить int local_k = K;
. Вам решать, как часто вы хотите перечитывать K
, т. Е. Какую область вы делаете / повторять local_k = K
в.
На x86 использование операнда источника памяти, который остается горячим в кеше L1d, вероятно, не является большой проблемой для производительности, но предотвратит автоматическую векторизацию.
Причина, по которой мне нужно это сделать, заключается в том, что исполняемый файл легко модифицируется учащимися, которым будет поручено «взломать» пример программы для изменения ее поведения. Упражнение должно быть достаточно простым для неопытных людей.
Для этот вариант использования, да volatile
именно то, что вы хотите. Повторное чтение всех данных из памяти на месте делает это немного проще, чем следование значению, кэшированному в регистре.
А производительность по сути не имеет значения, и вам не понадобится автоматическая векторизация. Вероятно, просто легкая оптимизация, чтобы студентам не приходилось разбираться с сохранением / перезагрузкой всего после каждого оператора C ++. Вроде бы у gcc -Og
было бы идеально.
С MSVC, возможно, попробуйте -O1
или -O2
и посмотрите, не смущает ли это что-нибудь. Я не думаю, что у него есть варианты для какой-то, но не слишком агрессивной оптимизации, это может быть либо отладочная сборка (хорошая для пошагового выполнения исходного кода C ++, плохая для чтения asm), либо полностью оптимизированная для размера или скорости.