¿Cómo se puede pasar "una expresión con efectos secundarios" a getc?

"Advanced Programming in the UNIX Environment, 3rd Edition", page 151:

The difference between getc and fgetc is that getc can be implemented as a macro, whereas fgetc cannot be implemented as a macro. This means three things:

  • The argument to getc should not be an expression with side effects.
  • Since fgetc is guaranteed to be a function, we can take its address. This allows us to pass the address of fgetc as an argument to another function.
  • Calls to fgetc probably take longer than calls to getc, as it usually takes more time to call a function.

¿Qué "expresión con efectos secundarios" puede ocurrir para las firmas de función con puntero de flujo como parámetro?

#include
int getc(FILE* stream);
int fgetc(FILE* stream);
0
Gracias, BLUEPIXY, Jim Balter.
agregado el autor Andrey Bushman, fuente
E.g ch = getc (filePointerArray [++ i])
agregado el autor BLUEPIXY, fuente
getc (foo ()) donde FILE * foo() {/ * efectos secundarios * /} . getc (strptr ++) donde FILE * strptr . getc (* pstrptr ++) donde FILE ** pstrptr . etc. Es realmente fácil encontrar ejemplos.
agregado el autor Jim Balter, fuente

2 Respuestas

Como un ejemplo, no escribas

FILE* foo() { puts( "Bah!\n" ); return stdout; }

void advance() { getc( foo() ); }
0
agregado
Este código funciona para mí. El error no se produce
agregado el autor Andrey Bushman, fuente
Sí, el "¡Bah!" fue impreso una vez para mi gcc (versión 4.8.1). Gracias.
agregado el autor Andrey Bushman, fuente
@Bush ¿Cuál es tu respuesta relevante? Preguntaste cómo una expresión con efectos secundarios se puede pasar a getc, y este es claramente un ejemplo. El texto que citó dice "getc se puede implementar como una macro": me doy cuenta de que el inglés no es su lengua materna, pero seguramente usted entiende lo que "puede" significa. Si llamaste por adelantado y no obtuviste más de un "¡Bah!" impreso, entonces la versión de getc que está utilizando no es una macro. (Puede verificarlo mirando stdio.h o macro expandiendo su fuente, por ejemplo, con gcc -E)
agregado el autor Jim Balter, fuente
@Bush: ausencia de garantía = posibilidad de malfuncionamiento, malfuncionamiento no garantizado
agregado el autor Cheers and hth. - Alf, fuente

Probablemente haya cientos de maneras de pasar una expresión con efectos secundarios, pero una "creíble" sería algo así como:

FILE *files[NUM_FILES];
...
int rc = getc(files[counter++]);

Si getc se implementa mal como una macro, la expresión files [counter ++] podría evaluarse más de una vez, lo que llevaría a un comportamiento inesperado.

0
agregado
"mal"? "¿Dudo que haya una biblioteca cuerdo?" No tienes idea de lo que estás hablando. La biblioteca stdio original y muchos de sus descendientes implementaron getc (f) como algo como - (f) -> ptr <(f) -> end? * (f) -> ptr ++: __getc (f) para la velocidad, por lo que se permite que getc sea una macro que reevalúa su argumento.
agregado el autor Jim Balter, fuente
Haga que - (f) -> cnt> 0? * (f) -> ptr ++: __getc (f)
agregado el autor Jim Balter, fuente
-1 re @JimBalter nota sobre "Si getc se implementa mal como una macro, los archivos de expresiones [contador ++] podrían evaluarse más de una vez, lo que llevaría a un comportamiento inesperado. Sin embargo, dudo que una biblioteca de C cuerdo cometería un error". . esta es una desinformación peligrosa para pasar.
agregado el autor Cheers and hth. - Alf, fuente