Обоснование объявления FILE * изменчивым для стандартного ввода в C

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

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

Вы спрашивали авторов этого программного обеспечения? Они должны знать.

the busybee 23.07.2024 08:21

Возможно, нет никакого обоснования. Программисты не всегда рациональны.

pmacfarlane 23.07.2024 08:27

«Память, на которую указывает fp, не меняется со стороны оборудования» Память, на которую указывает fp, не меняется volatile. fp сам по себе volatile. Ваш заголовок не соответствует коду, который вы показываете. FILE volatile * сильно отличается от FILE * volatile.

Gerhardh 23.07.2024 08:36

Правда, спасибо за указание на вводящую в заблуждение фразу! Указатель сам по себе изменчив, а не указатель памяти, на который ссылается (например, структура FILE).

Mosolov Sergey 23.07.2024 10:31

Кстати: ваш заголовок по-прежнему не соответствует коду в вашем вопросе. Возможно, вы захотите это исправить

Gerhardh 23.07.2024 14:23

Да, спасибо, что упомянули об этом, и спасибо stackoverflow.com/users/11294831/the-busybee за то, что это исправили :)

Mosolov Sergey 23.07.2024 15:10
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
6
126
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

FILE *volatile fp объявляет изменчивый указатель (т.е. fp является изменчивым) на объект FILE (мы не знаем, является ли этот тип изменчивым или нет). Следовательно, в этом контексте volatile необходим, если fp потенциально может быть изменен аппаратным обеспечением или другим обработчиком потока/прерывания. Однако, похоже, это не так. fp — локальная переменная, и ее адрес не передается другой функции.

Таким образом, декларация volatile в этом случае не требуется.

Существует случай, когда volatile необходим, даже если адрес объекта не передается и объект не изменяется в обработчике сигнала или аппаратно: когда вы хотите иметь возможность изменить его в отладчике и быть уверенным, что изменение будет использовано. и не подлежит обсуждению, поскольку компилятор сохранил значение в регистре или оптимизировал иным образом. Возможно, здесь не тот случай, но это возможно.

Eric Postpischil 23.07.2024 11:44

@EricPostpischil Это хороший момент. В этом случае я бы сделал объявление таким образом, чтобы было ясно, что оно предназначено для отладки, а не включало бы его в производственную сборку. В любом случае, volatile для корректного выполнения кода здесь не нужен.

nielsen 23.07.2024 12:30
Ответ принят как подходящий

Я предполагаю, что volatile здесь используется для взаимодействия с setjmp/longjmp — обратите внимание, что в main есть вызов setjmp. Из раздела ПРЕДОСТЕРЕЖЕНИЯ на странице руководства setjmp:

Компилятор может оптимизировать переменные в регистры, а функция longjmp() может восстановить значения. других регистров в дополнение к указателю стека и программному счетчику. Следовательно, значения автоматических переменных не указываются после вызова longjmp(), если они совпадают все следующие критерии:

• они являются локальными по отношению к функции, выполнившей соответствующий вызов setjmp();

• их значения изменяются между вызовами setjmp() и longjmp(); и

• они не объявлены как изменчивые.

Теперь в этом коде не видно, чтобы fp можно было изменить после вызова setjmp, если только один из вызовов fe_ на самом деле не является макросом, который изменяет fp. Таким образом, может показаться, что volatile на самом деле не нужен.

На самом деле это наиболее распространенное использование volatile для локальной (а не глобальной) переменной.

Хороший ответ. Это применение virtual было для меня новым (я не помню, чтобы когда-либо использовал setjmp/longjmp в серьезном коде, поскольку всегда считал его сомнительной конструкцией, что это только подтверждает). Мне до сих пор кажется странным, что fp объявлено virtual и, например. obj нет.

nielsen 24.07.2024 10:42

Другие вопросы по теме