Летучая и последовательная точка - PullRequest
0 голосов
/ 07 января 2019

С учетом следующего кода:

unsigned int global_flag = 0;

void exception_handle()
{
    global_flag = 1;
}

void func()
{
    /* access will cause exception which will assign global_flag = 1
       then execution continues */
    volatile unsigned int x = *(unsigned int *)(0x60000000U); /* memory protection unit configured to raise exception upon accessing this address */

    if (global_flag == 1)
    {
        /* some code */
    }
}

Учитывая тот факт, что volatile нельзя переупорядочивать по точкам последовательности :

Минимальное требование заключается в том, чтобы в точке последовательности все предыдущие доступ к летучим объектам стабилизировался, и никаких последующих доступы произошли

И учитывая следующее о точках последовательности :

Точки последовательности встречаются в следующих местах ... (1) .. (2) .. (3) В конце полного выражения . Эта категория включает в себя выражение операторы (такие как присваивание a = b ;), операторы возврата, управляющие выражения if , операторы switch, while или do-while, и все три выражения в выражении for.

Обещано ли, что volatile unsigned int x = *(unsigned int *)(0x60000000U); будет иметь место до if (global_flag == 1) (в двоичном ассмблере выполнение CPU не по порядку здесь не актуально)?

Согласно приведенным выше цитатам, volatile unsigned int x = *(unsigned int *)(0x60000000U); должен быть оценен до конца следующей точки последовательности, а volatile unsigned int x = *(unsigned int *)(0x60000000U); является самой точкой последовательности, поэтому это означает, что каждое назначение volatile оценивается во время назначения

Если ответ на поставленный выше вопрос - нет, то следующая точка последовательности находится на конце if, означает ли это, что может быть выполнено что-то подобное:

if (global_flag == 1)
{
    volatile unsigned int x = *(unsigned int *)(0x60000000U);
    /* some code */
}

Система представляет собой встроенную одноядерную кору m0, одноядерное, однопоточное приложение.

Ответы [ 2 ]

0 голосов
/ 07 января 2019

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

(Также обратите внимание, что в выражении *(unsigned int *)(0x60000000U) нет спецификатора volatile. Я думаю, что это действительно то выражение, которое вы хотите обработать специально, но ваш код этого не делает. Компилятору разрешено создавать код он оценивает *(unsigned int *)(0x60000000U) заблаговременно, затем выполняет кучу других вещей, которые он имеет на своей пластине, затем присваивает полученное значение x, и это будет удовлетворять ограничениям, которые стандарты C накладывают на значения volatile l. )

Если бы в вашем фрагменте было unsigned int volatile global_flag = 0; и *(volatile unsigned int *)(0x60000000U), то ответ на вопрос «Это обещано, что…» был бы однозначным «да».

0 голосов
/ 07 января 2019

Обещано ли, что volatile unsigned int x = * (unsigned int *) (ILLEGAL_ADDRESS); произойдет раньше, если (global_flag == 1)

Из информативного C11 ПриложениеC (добавлены новые строки / форматирование для удобства чтения):

Ниже приведены точки последовательности, описанные в 5.1.2.3:
. ...
- Между оценкой полного выражения и следующим полным выражением, которое будет оценено.
- Ниже приведены полные выражения:
- инициализатор, который не является частью составного литерала (6.7.9);
- выражение в выражении выражения (6.8.3);
- управляющее выражение оператора выбора (если или переключатель) (6.8.4);
- управляющее выражение оператора while или do (6.8.5);
- каждое из (необязательных) выражений оператора for (6.8.5.3);
- (необязательное) выражение в операторе возврата (6.8.6.4).

Поскольку *(unsigned int *)(ILLEGAL_ADDRESS); является инициализатором (выражением присваивания), а инициализатор не является частью составного литерала, он является полным выражением. Следующим полным выражением является управляющий оператор в if, поэтому между if и инициализацией x существует точка последовательности.

А из знаменитого C11 5.1.2.3p6 :

Минимальные требования к соответствующей реализации:

Доступ к летучим объектам оценивается строго в соответствии с правилами абстрактной машины.
...

Поскольку x является летучим объектом, он инициализируется строго на абстрактной машине, поэтому после точки последовательности он должен иметь значение r, равное результату операции *(unsigned int *)(ILLEGAL_ADDRESS).

Так что да, инициализация объекта x должна произойти до того, как контрольное выражение внутри if.

На неопределенное поведение есть хорошая цитата из C11 6.5.3.2p4 :

Если указателю присвоено недопустимое значение, поведение унарного оператора * не определено.

Как вы прокомментировали:

доступ к адресу 0x60000000 не разрешен в моей модели системной памяти

можно сделать вывод, что (unsigned int*)0x60000000 является недопустимым указателем, поэтому унарный оператор * должен порождать драконов .

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