Search code examples
cstdinvolatile

Rationale behind declaring FILE * volatile to stdin in C


I wonder what reason might be to declare FILE *volatile fp as volatile pointer:

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;
}

Source: https://github.com/rxi/fe/blob/ed4cda96bd582cbb08520964ba627efb40f3dd91/src/fe.c#L854

The pointer fp is not changing from hardware side or in interrupts by any means. It seems not changing in signal handlers either.

Projects seems to me as well written and I guess there's some reason behind that I can't understand. Please, provide some clues about that.


Solution

  • I would guess that volatile is being used here for its interaction with setjmp/longjmp -- notice that there is a call to setjmp in main. From the CAVEATS section of the setjmp manual page:

    The compiler may optimize variables into registers, and longjmp() may restore the values of other registers in addition to the stack pointer and program counter. Consequently, the values of automatic variables are unspecified after a call to longjmp() if they meet all the following criteria:

    • they are local to the function that made the corresponding setjmp() call;

    • their values are changed between the calls to setjmp() and longjmp(); and

    • they are not declared as volatile.

    Now in this code it does not appear that fp can be changed after the call to setjmp, unless one of the fe_ calls is actually a macro that modifies fp. So it would appear that the volatile is actually unnecessary.

    This is actually the most common use of volatile for a local (rather than global) variable.