read - ¿Por qué el "fopen" de C toma un "const char*" como segundo argumento?
read file c line by line (7)
Siempre me ha parecido extraño que la función C "fopen" tome un "const char *" como segundo argumento. Creo que sería más fácil tanto leer el código como implementar el código de la biblioteca si hubiera máscaras de bits definidas en stdio.h, como "IO_READ" y demás, para poder hacer cosas como:
FILE* myFile = fopen("file.txt", IO_READ | IO_WRITE);
¿Hay alguna razón programática para la forma en que realmente es, o es solo histórica? (es decir, "Así es como es").
EDITAR Gracias por las explicaciones de todos. La respuesta correcta es probablemente entre las dadas.
Como dice Tuomas Pelkonen, es un legado.
Personalmente, me pregunto si algunos saps erróneos lo concibieron como mejor debido a la cantidad de caracteres escritos. En los viejos tiempos el tiempo de los programadores se valoraba más de lo que es hoy, ya que era menos accesible y los compiladores no eran tan buenos y todo eso.
Esto es solo una especulación, pero puedo ver por qué algunas personas preferirían guardar algunos caracteres aquí y allá (nótese la falta de verbosidad en cualquiera de los nombres de funciones de la biblioteca estándar ... Presento str.tr y strchr de string.h como probablemente los mejores ejemplos de brevedad innecesaria).
Debo decir que estoy agradecido por ello, sé escribir "r" en lugar de IO_OPEN_FLAG_R o fue IOFLAG_R o SYSFLAGS_OPEN_RMODE o lo que sea
Dennis Ritchie tiene esto que decir, de http://cm.bell-labs.com/cm/cs/who/dmr/chist.html
En particular, Lesk escribió un ''paquete de E / S portátil'' [Lesk 72] que luego fue rediseñado para convertirse en las rutinas de ''E / S estándar''.
Entonces le pregunto a Mike Lesk , publique el resultado aquí como una respuesta a su propia pregunta, y gane un montón de puntos por ello. Aunque es posible que desee hacer que la pregunta suene un poco menos como crítica ;-)
Me gustaría especular que se trata de uno o más de los siguientes (desafortunadamente, no pude encontrar rápidamente ningún tipo de referencias de apoyo, por lo que probablemente esto siga siendo especulación):
- A Kernighan o Ritchie (o a quien se le ocurrió la interfaz para
fopen()
) le gustó la idea de especificar el modo usando una cadena en lugar de un mapa de bits - Es posible que quisieran que la interfaz fuera similar pero notablemente diferente de la interfaz de llamada al sistema Unix
open()
, por lo que sería familiar a la vez pero no se compilaría por error con las constantes definidas para Unix en lugar de la biblioteca C
Por ejemplo, digamos que el mítico estándar C fopen()
que tomó un parámetro de modo OPENMODE_READONLY
usó el identificador OPENMODE_READONLY
para especificar que el archivo que hoy se especifica con la cadena de modo "r". Ahora, si alguien realizó la siguiente llamada en un programa compilado en una plataforma Unix (y se ha incluido el encabezado que define O_RDONLY
):
fopen( "myfile", O_RDONLY);
No habría error de compilación, pero a menos que se OPENMODE_READONLY
y O_RDONLY
como el mismo bit, se obtendría un comportamiento inesperado. Por supuesto, tendría sentido que los nombres estándar C se definieran de la misma manera que los nombres Unix, pero tal vez querían evitar la necesidad de este tipo de acoplamiento.
Por otra parte, esto podría no haber cruzado sus mentes en absoluto ...
Una palabra: legado. Lamentablemente tenemos que vivir con eso.
Solo especulación: Tal vez en ese momento un "const char *" parecía una solución más flexible, porque no está limitada de ninguna manera. Una máscara de bits solo puede tener 32 valores diferentes. Me parece un YAGNI ahora.
Más especulaciones: los tipos eran flojos y escribir "rb" requiere menos tipeo que MASK_THIS | MASK_THAT :)
Creo que una de las ventajas de la cadena de caracteres en lugar de una simple máscara de bits es que permite extensiones específicas de plataforma que no son configuraciones de bits. Puramente hipotético
FILE *fp = fopen("/dev/something-weird", "r+:bs=4096");
Para este gizmo, la llamada a open()
necesita contar el tamaño del bloque, y las diferentes llamadas pueden usar tamaños radicalmente diferentes, etc. Concedido, la E / S se ha organizado bastante bien ahora (ese no era el caso originalmente: los dispositivos eran enormemente diversos y los mecanismos de acceso lejos de estar unificados), por lo que rara vez parece ser necesario. Pero la cadena de opciones con valores de cadena permite una extensibilidad mucho mejor.
El subyacente open()
tiene que ser aumentado por la ioctl()
(control de E / S) llamada o funciones que lo ocultan para lograr efectos similares.
La primera referencia de fopen
que encontré está en la primera edición de "The C Programming Language" de Kernighan & Ritchie (K & R1), publicada en 1978.
Muestra una implementación de muestra de fopen
, que presumiblemente es una versión simplificada del código en la implementación de la biblioteca estándar C de la época. Aquí hay una versión abreviada del código del libro:
FILE *fopen(name, mode)
register char *name, *mode;
{
/* ... */
if (*mode != ''r'' && *mode != ''w'' && *mode != ''a'') {
fprintf(stderr, "illegal mode %s opening %s/n",
mode, name);
exit(1);
}
/* ... */
}
Al observar el código, se esperaba que el mode
fuera una cadena de 1 carácter (no "rb"
, sin distinción entre texto y binario). Si pasó una cadena más larga, cualquier carácter pasado al primero se ignoró silenciosamente. Si pasó un mode
no válido, la función imprimiría un mensaje de error y terminaría su programa en lugar de devolver un puntero nulo (supongo que la versión de la biblioteca real no hizo eso). El libro enfatizó el código simple sobre la comprobación de errores.
Es difícil estar seguro, especialmente dado que el libro no pasa mucho tiempo explicando el parámetro de mode
, pero parece que se definió como una cadena por conveniencia. Un solo personaje también habría funcionado, pero una cadena al menos hace posible la expansión futura (algo que el libro no menciona).