...
This code calls the getc() function with an expression as the stream argument. If getc() is implemented as a macro, the file may be opened several times. (See rule FIO31-C. Do not open a file that is already open.)
| Code Block | ||||
|---|---|---|---|---|
| ||||
char *file_name;
FILE *fptr;
/* Initialize file_name */
int c = getc(fptr = fopen(file_name, "r"));
if (c == EOF) {
/* Handle error */
}
|
...
In this compliant solution, getc() is no longer called with an expression as its argument and the value returned by fopen() is checked for errors.
| Code Block | ||||
|---|---|---|---|---|
| ||||
int c;
char *file_name;
FILE *fptr;
/* Initialize file_name */
fptr = fopen(file_name, "r");
if (fptr == NULL) {
/* Handle error */
}
c = getc(fptr);
if (c == EOF) {
/* Handle error */
}
|
...
In this noncompliant example, putc() is called with an expression as the stream argument. If putc() is implemented as a macro, the expression can be evaluated several times within the macro expansion of putc() with unintended results.
| Code Block | ||||
|---|---|---|---|---|
| ||||
char *file_name;
FILE *fptr = NULL;
/* Initialize file_name */
int c = 'a';
while (c <= 'z') {
if (putc(c++, fptr ? fptr :
(fptr = fopen(file_name, "w")) == EOF) {
/* Handle error */
}
}
|
...
In the compliant solution, the stream argument to putc() no longer has side effects.
| Code Block | ||||
|---|---|---|---|---|
| ||||
char *file_name;
/* Initialize file_name */
FILE *fptr = fopen(file_name, "w");
if (fptr == NULL) {
/* Handle error */
}
int c = 'a';
while (c <= 'z') {
if (putc(c++, fptr) == EOF) {
/* Handle error */
}
}
|
...