While reading the getc
man page, I came across:
may be implemented as a macro which evaluates stream more than once.
So, getc
might be implemented as a function as well - what exactly means by evaluates stream more than once?
CodePudding user response:
Consider a function:
FILE *getstream(void);
And a code:
int c = getc(getstream());
In case getc
is a function, getstream
will be called only once, its result will be stored in a temporary variable/register and passed to getc
.
In case getc
is a macro, let say something like:
#define getc(s) ((s) == NULL) ? -1 :_getc(s))
it will get expanded into:
int c = (((getstream()) == NULL) ? -1 :_getc(getstream()));
That is it will call getstream()
twice. In case getstream
has some side effects (using IO, modifying some global state), the flow of the program will be different between the two cases and one must be aware of this.
CodePudding user response:
This means that the expression passed to getc
as an argument could be evaluated multiple times. So if this expression contains an assignment, increment/decrement, or function call, it will happen more than once.
For example, given this macro:
#define PRINT_INT(x) printf("%d (%x)\n", (x), (x))
This code:
int x = 3;
PRINT_INT( x);
Will expand to:
int x = 3;
printf("%d (%x)\n", ( x), ( x))
This would cause x
to get incremented more than once without a sequence point and trigger undefined behavior.
The man page is saying that getc
may be doing something similar, so don't pass anything to it that could have a side effect.
CodePudding user response:
You must not suppose that getc's argument is evaluated conforming to a function-call discipline (call-by-value in this case).
This comes from the paragraph "7.19.7.5 The getc function" the ISO 9899 that defines the C language:
The getc function is equivalent to fgetc, except that if it is implemented as a macro, it may evaluate stream more than once, so the argument should never be an expression with side effects
The definitions of the libc functions that you find in the linux man pages come from a combination of sources that vary between the ISO9899, POSIX, etc (see the CONFORMING TO
paragraphs from each manual to see the origin of the definitions).
CodePudding user response:
The short answer is that if you were to write something like
int c = getc(fp[i ]);
you would potentially run into big trouble, because the getc
macro might evaluate its argument fp[i ]
twice, meaning not only that i
would potentially get bumped by 2, but also because (in the absence of sequence points) you'd descend all the way into formally undefined behavior.
But if you never call getc
on an argument with a side effect, it's perfectly safe.
For some reason, I see people calling fgetc
more and more often these days. Presumably they're being taught this because it's "safer", although to my mind, it's a pretty unnecessary concern in the grand scheme of things.
See also getc() vs fgetc() - What are the major differences?.