Интересно, по какой причине можно объявить FILE *volatile fp
изменчивым указателем:
int main(int argc, char **argv) {
int gc;
fe_Object *obj;
FILE *volatile fp = stdin;
fe_Context *ctx = fe_open(buf, sizeof(buf));
/* init input file */
if (argc > 1) {
fp = fopen(argv[1], "rb");
if (!fp) { fe_error(ctx, "could not open input file"); }
}
if (fp == stdin) { fe_handlers(ctx)->error = onerror; }
gc = fe_savegc(ctx);
setjmp(toplevel);
/* re(p)l */
for (;;) {
fe_restoregc(ctx, gc);
if (fp == stdin) { printf("> "); }
if (!(obj = fe_readfp(ctx, fp))) { break; }
obj = fe_eval(ctx, obj);
if (fp == stdin) { fe_writefp(ctx, obj, stdout); printf("\n"); }
}
return EXIT_SUCCESS;
}
Источник: https://github.com/rxi/fe/blob/ed4cda96bd582cbb08520964ba627efb40f3dd91/src/fe.c#L854
Указатель fp
никоим образом не меняется ни аппаратно, ни в прерываниях. Кажется, это не меняется и в обработчиках сигналов.
Мне кажется, что проекты тоже хорошо написаны, и я думаю, что есть какая-то причина, которую я не могу понять. Пожалуйста, дайте некоторые подсказки по этому поводу.
Возможно, нет никакого обоснования. Программисты не всегда рациональны.
«Память, на которую указывает fp, не меняется со стороны оборудования» Память, на которую указывает fp
, не меняется volatile
. fp
сам по себе volatile
. Ваш заголовок не соответствует коду, который вы показываете. FILE volatile *
сильно отличается от FILE * volatile
.
Правда, спасибо за указание на вводящую в заблуждение фразу! Указатель сам по себе изменчив, а не указатель памяти, на который ссылается (например, структура FILE).
Кстати: ваш заголовок по-прежнему не соответствует коду в вашем вопросе. Возможно, вы захотите это исправить
Да, спасибо, что упомянули об этом, и спасибо stackoverflow.com/users/11294831/the-busybee за то, что это исправили :)
FILE *volatile fp
объявляет изменчивый указатель (т.е. fp
является изменчивым) на объект FILE
(мы не знаем, является ли этот тип изменчивым или нет). Следовательно, в этом контексте volatile
необходим, если fp
потенциально может быть изменен аппаратным обеспечением или другим обработчиком потока/прерывания. Однако, похоже, это не так. fp
— локальная переменная, и ее адрес не передается другой функции.
Таким образом, декларация volatile
в этом случае не требуется.
Существует случай, когда volatile
необходим, даже если адрес объекта не передается и объект не изменяется в обработчике сигнала или аппаратно: когда вы хотите иметь возможность изменить его в отладчике и быть уверенным, что изменение будет использовано. и не подлежит обсуждению, поскольку компилятор сохранил значение в регистре или оптимизировал иным образом. Возможно, здесь не тот случай, но это возможно.
@EricPostpischil Это хороший момент. В этом случае я бы сделал объявление таким образом, чтобы было ясно, что оно предназначено для отладки, а не включало бы его в производственную сборку. В любом случае, volatile
для корректного выполнения кода здесь не нужен.
Я предполагаю, что volatile
здесь используется для взаимодействия с setjmp
/longjmp
— обратите внимание, что в main есть вызов setjmp
. Из раздела ПРЕДОСТЕРЕЖЕНИЯ на странице руководства setjmp:
Компилятор может оптимизировать переменные в регистры, а функция longjmp() может восстановить значения. других регистров в дополнение к указателю стека и программному счетчику. Следовательно, значения автоматических переменных не указываются после вызова longjmp(), если они совпадают все следующие критерии:
• они являются локальными по отношению к функции, выполнившей соответствующий вызов setjmp();
• их значения изменяются между вызовами setjmp() и longjmp(); и
• они не объявлены как изменчивые.
Теперь в этом коде не видно, чтобы fp
можно было изменить после вызова setjmp
, если только один из вызовов fe_
на самом деле не является макросом, который изменяет fp
. Таким образом, может показаться, что volatile
на самом деле не нужен.
На самом деле это наиболее распространенное использование volatile
для локальной (а не глобальной) переменной.
Хороший ответ. Это применение virtual
было для меня новым (я не помню, чтобы когда-либо использовал setjmp
/longjmp
в серьезном коде, поскольку всегда считал его сомнительной конструкцией, что это только подтверждает). Мне до сих пор кажется странным, что fp
объявлено virtual
и, например. obj
нет.
Вы спрашивали авторов этого программного обеспечения? Они должны знать.