c - ¿Por qué el tipo de retorno para ftell no es fpos_t?
c99 (4)
Según C99, el prototipo de
ftell
es:
long int ftell(FILE *stream);
Por lo que entiendo, debería ser lo siguiente:
fpos_t ftell(FILE *stream);
¿Porqué es eso?
De §7.19.1-2
fpos_t
que es un tipo de objeto distinto de un tipo de matriz capaz de registrar toda la información necesaria para especificar de forma única cada posición dentro de un archivo.
Entiendo que
fpos_t
debe usarse para registrar una posición dentro de un archivo.
Entonces
ftell
que devuelve una posición dentro de un archivo debe ser de ese tipo.
En cambio es:
-
signed
-
de tipo
long
que puede ser demasiado pequeño o demasiado grande para acceder a un archivo en ciertas arquitecturas.
Desde la página de
fgetpos()/fsetpos()
de
fgetpos()/fsetpos()
:
En algunos sistemas que no son UNIX, un objeto fpos_t puede ser un objeto complejo y estas rutinas pueden ser la única forma de reposicionar de forma portátil un flujo de texto.
mientras que
ftell()
es necesario para devolver el desplazamiento del puntero del archivo en el archivo.
Estas son interfaces completamente diferentes.
El uso más probable de eso es permitir valores de retorno de error como números negativos.
Es lo mismo que la familia de funciones
printf
, que devuelve
ssize_t
lugar de
size_t
, que resulta ser una versión
signed
de
size_t
.
El primero de estos trucos ocurrió con
getchar()
, que devuelve
int
lugar de
char
, para permitir que el valor devuelto al final de la condición de archivo (
EOF
), que normalmente es un valor negativo, contrasta con el conjunto completo de posibles caracteres devueltos (en el rango de
0
a
255
, todos los enteros positivos)
¿Por qué no define una extensión firmada del mismo tipo para permitir
-1
?
En realidad no lo sé :)
Razones históricas.
fseek
y
ftell
son funciones muy antiguas, anteriores a la estandarización de C.
Asumen que el
long
es lo suficientemente grande como para representar una posición en cualquier archivo, una suposición que probablemente era válida en ese momento.
long
es de al menos 32 bits, y
obviamente
no podría tener un solo archivo mayor de 2 gigabytes (o incluso
1.21 gigabytes
).
Cuando se publicó el primer estándar C (ANSI C, 1989), se estaba haciendo evidente que esta suposición ya no era válida, pero cambiar las definiciones de
fseek
y
ftell
habría roto el código existente.
Además, todavía no había un tipo entero más ancho que
long
(
long long
no se introdujo hasta C99).
El comité ANSI C decidió que
fseek
y
ftell
seguían siendo útiles, pero introdujeron nuevas funciones de posicionamiento de archivos
fsetpos
y
fgetpos
.
Estas funciones utilizan un tipo opaco no numérico
fpos_t
lugar de
long
, lo que los hace más y menos flexibles que
fseek
y
ftell
.
Una implementación puede definir
fpos_t
para que pueda representar cualquier posible desplazamiento de archivo, pero dado que es un tipo no numérico,
fsetpos
y
fgetpos
no proporcionan la función
SEEK_SET
/
SEEK_CUR
/
SEEK_END
.
Por ejemplo, no hay forma de usar
fsetpos
para colocar un archivo hasta el final.
Algo de esto se aborda en el ANSI C Justificación, sección 4.9.9 :
Dadas estas restricciones, el Comité aún consideró que esta función [
fseek
] tiene suficiente utilidad y se utiliza en un código existente suficiente para garantizar su retención en la Norma. Se han agregadofgetpos
yfsetpos
para manejar archivos que son demasiado grandes para manejar confseek
yftell
.
Si esto se definiera desde cero hoy en día, probablemente habría un solo par de funciones que cubrirían toda la funcionalidad de las cuatro funciones actuales, probablemente utilizando un tipo entero tipo
typedef
ed requerido para ser lo suficientemente grande como para representar cualquier posible desplazamiento de archivo.
(Con los sistemas actuales, es probable que 64 bits sean suficientes, pero no me sorprendería ver archivos de 8 exabytes antes de demasiado tiempo en sistemas grandes).
Tenga en cuenta que
fpos_t
es
[...] un tipo de objeto completo que no sea un tipo de matriz capaz de registrar toda la información necesaria para especificar de forma única cada posición dentro de un archivo.
¡Entonces puede ser incluso una estructura, totalmente inutilizable para cualquier otra cosa además de llamar a
fsetpos
!
Por otro lado, el valor de retorno de
ftell
es un escalar que se garantiza su uso para indicar la posición exacta de bytes en un archivo binario:
Para una secuencia binaria, el valor es el número de caracteres desde el comienzo del archivo.
Aparte de eso, la razón es
la compatibilidad con versiones anteriores
.
ftell
debutó en C89, y quizás entonces la expectativa era que el
long
se escalaría lo suficientemente rápido como para contener todos los tamaños de archivo, algo que no siempre es cierto hoy en día.
Desafortunadamente, no es posible cambiar el tipo devuelto por
ftell
pero es demasiado tarde para cambiar eso ahora, incluso aquellas plataformas que admiten archivos más grandes ahora tienen funciones con otro nombre, como
ftello
.
se requiere la firma porque la función devuelve
-1
en caso de error.