Гарантируется ли `* (volatile T *) 0x1234;` переводом в инструкцию чтения? - PullRequest
0 голосов
/ 06 декабря 2018

При работе с оборудованием иногда требуется выполнить чтение из определенного регистра, отбрасывая фактическое значение (например, для сброса некоторых флагов).Одним из способов было бы явное чтение и отбрасывание значения, например:

int temp = *(volatile int*)0x1234; // 0x1234 is the register address
(void)temp;                          // To silence the "unused" warning

Другой способ, который, кажется, работает, это просто:

*(volatile int*)0x1234;

Но это, очевидно, не подразумеваетдоступ read , но на компиляторах, которые я проверял, это похоже на один.Это гарантировано стандартом?

Пример для ARM GCC с -O3: https://arm.godbolt.org/z/9Vmt6n

void test(void)
{
    *(volatile int *)0x1234;
}

переводится в

test():
        mov     r3, #4096
        ldr     r3, [r3, #564]
        bx      lr

Ответы [ 2 ]

0 голосов
/ 06 декабря 2018

Документация gcc по volatile сообщает нам, что условия, по которым осуществляется энергозависимый доступ, определяются реализацией:

C имеет концепцию энергозависимых объектов.К ним обычно обращаются указатели и они используются для доступа к аппаратным средствам или связи между потоками.Стандарт поощряет компиляторы воздерживаться от оптимизаций, связанных с доступом к изменчивым объектам, но оставляет его реализацию определенной относительно того, что составляет изменчивый доступ .Минимальное требование состоит в том, чтобы в точке последовательности все предыдущие обращения к изменчивым объектам стабилизировались, и никаких последующих обращений не происходило.Таким образом, реализация может свободно изменять порядок и комбинировать изменчивые обращения, которые происходят между точками последовательности, но не может делать это для обращений через точку последовательности.Использование volatile не позволяет нарушать ограничение на обновление объектов несколько раз между двумя точками последовательности.

Это поддерживается секцией C11 6.7.3 Спецификаторы типа p7 :

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

В документе gcc указывается, как volatile работает для gcc, в случае, аналогичном вашему:

Скалярvolatile объект читается, когда к нему обращаются в пустом контексте:

volatile int *src = somevalue;
*src;

Такие выражения являются rvalues, и GCC реализует это как чтение изменяемого объекта, на который указывает.

0 голосов
/ 06 декабря 2018

C 2018 6.7.3 8 гласит:

Объект, имеющий тип с изменчивой квалификацией, может быть изменен способами, неизвестными для реализации, или иметь другие неизвестные побочные эффекты.Поэтому любое выражение, относящееся к такому объекту, должно оцениваться строго в соответствии с правилами абстрактной машины, как описано в 5.1.2.3.…

Поскольку *(volatile int*)0x1234; является выражением, относящимся к объекту сТип volatile-квалифицирован, оценивая его, должен получить доступ к объекту(Это предполагает, что 0x1234 обозначает действительную ссылку на некоторый объект в реализации C, конечно.)

Per C 2018 5.1.2.3 4:

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

Согласно C 2018 6.5 1:

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

Таким образом, выражение определяет вычисление значения.Пункт 5.1.2.3 4 говорит нам, что эта оценка выполняется абстрактной машиной, а 6.7.3 8 говорит нам, что фактическая реализация выполняет эту оценку, которую выполняет машина абстракции.

Одно предостережение состоит в том, что составляет «доступ».»Определяется реализацией.«Доступ», как определено стандартом C, включает в себя как чтение, так и запись (C 3.1 1), но стандарт C не может указать, что он означает чтение или запись на некоторый конкретный аппаратный компонент.

На ходудалее на language-lawyer, территория, C 6.3.2.1 2 говорит нам:

За исключением случаев, когда это операнд оператора sizeof, унарный оператор &, оператор ++оператор -- или левый операнд оператора . или оператор присваивания, lvalue, у которого нет типа массива, преобразуется в значение, хранящееся в назначенном объекте (и больше не является lvalue);это называется преобразованием lvalue.

Таким образом, поскольку *(volatile int*)0x1234; является lvalue, посредством оператора * и не является операндом перечисленных операторов, оно преобразуется в значениехранится в объекте.Таким образом, это выражение указывает вычисление значения, которое хранится в объекте.

...