volatile register int

126
24 августа 2021, 17:30

Имеет ли смысл такая запись?

volatile register int x;

С одной стороны, она компилируется, а с другой - я тут вспоминаю и вроде бы register не заставляет компилятор размещать переменную в регистре, а лишь даёт рекомендацию, которую компилятор в праве проигнорировать? И вообще, эти два требования (volatile и register) независимы или как-то взаимодействуют?

PS: Идея заставить компилятор отключить все оптимизации, связанные с переменной, но при этом держать её в регистре с целью замера производительности.

Answer 1

И вообще, эти два требования (volatile и register) независимы или как-то взаимодействуют?

Да, независимы:

  • volatile — это квалификатор типа (type qualifiers), он говорит компилятору, что делать, когда переменной что-то присваивают (когда она является l-value). Другие — это const и restrict (в C99+).
  • register — это спецификатор класса памяти (storage-class specifier). Он говорит компилятору, где разместить память под переменную. Другие — это static, extern, auto (в С), а также де-стандарто typedef (не по смыслу, но так было проще описать грамматику языка). Оных в объявлении переменной может быть не более одного.

register не заставляет компилятор размещать переменную в регистре, а лишь даёт рекомендацию, которую компилятор в праве проигнорировать?

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

В силу практически полной бесполезности использование этого ключевого слова объявили нежелательным (deprecated) в С++11 и полностью выкинули из последнего стандарта (С++17).

На вскидку, на сегодня я бы сказал, что практическая польза от этого слова только одна — низкоуровневый код в gcc с использованием расширенных ассемблерных вставок, чтобы привязать её к конкретному регистру.

PS: Идея заставить компилятор отключить все оптимизации, связанные с переменной, но при этом держать её в регистре с целью замера производительности.

Почти наверняка не рабочая идея — даже если компилятор действительно разместит переменную в регистре, он не будет уважать все действия с переменной, а только сохранение и загрузку в неё данных, что может смазать результаты замеров.

Для таких тонких целей единственный выход — использовать ассемблерные вставки. Во всех противных случаях нельзя контролировать, что именно заменяется.

Answer 2

Си стандарт 6.7.1 :

A declaration of an identifier for an object with storage-class specifier register suggests that access to the object be as fast as possible. The extent to which such suggestions are effective is implementation-defined.

The implementation may treat any register declaration simply as an auto declaration. However, whether or not addressable storage is actually used, the address of any part of an object declared with storage-class specifier register cannot be computed, either explicitly (by use of the unary & operator as discussed in 6.5.3.2) or implicitly (by converting an array name to a pointer as discussed in 6.3.2.1). Thus, the only operators that can be applied to an array declared with storage-class specifier register are sizeof and _Alignof.

Переменная со знаком register намекает компилятору работать с ней как можно быстрее. Адрес регистровой переменной брать нельзя. Но компиляторы могут реализовать переменную в памяти, а могут в процессорных ячейках.

Си стандарт 6.7.3 :

An object that has volatile-qualified type may be modified in ways unknown to the implementation or have other unknown side effects. Therefore any expression referring to such an object shall be evaluated strictly according to the rules of the abstract machine, as described in 5.1.2.3. Furthermore, at every sequence point the value last stored in the object shall agree with that prescribed by the abstract machine, except as modified by the unknown factors mentioned previously. 134) What constitutes an access to an object that has volatile-qualified type is implementation-defined.

A volatile declaration may be used to describe an object corresponding to a memory-mapped input/output port or an object accessed by an asynchronously interrupting function. Actions on objects so declared shall not be ‘‘optimized out’’ by an implementation or reordered except as permitted by the rules for evaluating expressions.

Переменная со знаком volatile имеет способность менять значение неизвестным компилятору способом. По-этому компилятор постоянно читает и записывает значения в память.

Одновременная декларация register volatile указывает обязательно записывать значения. А планы register всего-лишь были увеличить скорость, но не место хранения.

Ваши надежды могут быть реализованы наверно только ассемблером.

READ ALSO
Угол между камерами с проекционной матрицей 3x4

Угол между камерами с проекционной матрицей 3x4

Есть проекционная матрица 3x4 полученная из R и T в результате стерео калибровки камерыКак из нее получить угол между камерами?

83
Что такое lparam в WM_SETCURSOR?

Что такое lparam в WM_SETCURSOR?

Что такое lparam в WM_SETCURSOR в моём случае lparam равен 0x2000001, а что это такое и существует какой то макрос для 0x2000001?

82
SendMessageCallback не вызывает функцию callback

SendMessageCallback не вызывает функцию callback

Не могу понять в чём может быть ошибкаКод ниже никогда не вызывает функцию ResultCallBack

87
Инициализация внутри if

Инициализация внутри if

В 17 стандарте появилась возможность инициализировать переменную внутри условия if (init; condition) Значит я могу сделать так if(int i =12; d < i){} или...

127