Интересно, по какой причине можно объявить 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 нет.
Вы спрашивали авторов этого программного обеспечения? Они должны знать.