¿Puede sizeof(int) alguna vez ser 1 en una implementación alojada?
(8)
Mi opinión es que una implementación C no puede satisfacer la especificación de ciertas funciones stdio
(particularmente fputc
/ fgetc
) if sizeof(int)==1
, ya que el int
necesita poder contener cualquier valor posible de unsigned char
o EOF
(-1 ) ¿Es este razonamiento correcto?
(Obviamente sizeof(int)
no puede ser 1 si CHAR_BIT
es 8, debido al rango mínimo requerido para int
, por lo que implícitamente solo hablamos de implementaciones con CHAR_BIT>=16
, por ejemplo DSP, donde las implementaciones típicas serían una implementación independiente en lugar de una implementación alojada, y por lo tanto no se requiere para proporcionar stdio
.)
Editar : Después de leer las respuestas y algunas referencias de enlaces, algunas reflexiones sobre las formas en que podría ser válida para una implementación alojada tener sizeof(int)==1
:
Primero, algunas citas:
7.19.7.1 (2-3):
Si el indicador de fin de archivo para el flujo de entrada señalado por el flujo no está configurado y el siguiente carácter está presente, la función fgetc obtiene dicho carácter como un carácter sin signo convertido a un int y avanza el indicador de posición del archivo asociado para el flujo (si está definido).
Si se establece el indicador de fin de archivo para la secuencia, o si la secuencia se encuentra al final del archivo, se establece el indicador de fin de archivo para la secuencia y la función fgetc devuelve EOF. De lo contrario, la función fgetc devuelve el siguiente carácter de la secuencia de entrada a la que apunta la transmisión. Si se produce un error de lectura, se establece el indicador de error para la secuencia y la función fgetc devuelve EOF.
7.19.8.1 (2):
La función fread lee, en la matriz apuntada por ptr, hasta elementos nmemb cuyo tamaño se especifica por tamaño, desde la secuencia a la que apunta la transmisión. Para cada objeto, se realizan llamadas de tamaño a la función fgetc y los resultados se almacenan, en el orden leído, en una matriz de caracteres sin signo que se superpone exactamente al objeto. El indicador de posición del archivo para la transmisión (si está definido) avanza por la cantidad de caracteres leídos con éxito.
Pensamientos:
La lectura de valores de
unsigned char
fuera del rango deint
podría simplemente teneruncomportamientoindefinidodefinido por la implementación en la implementación. Esto es particularmente inquietante, ya que significa que usarfwrite
yfread
para almacenar estructuras binarias (que si bien da como resultado archivos no portables, se supone que es una operación que puede realizar de forma portátil en cualquier implementación) podría funcionar pero fallará silenciosamente.esencialmente siempre resulta en un comportamiento indefinido .Acepto que una implementación puede no tener un sistema de archivos utilizable, pero es mucho más difícil aceptar que una implementación pueda tener un sistema de archivos que invoca automáticamente demonios nasales tan pronto como intentes usarlo, y no hay manera de determinar que no se puede usar.Ahora que me doy cuenta de que el comportamiento está definido por la implementación y no está indefinido, no es tan inquietante, y creo que esto podría ser una implementación válida (aunque no deseable).Un
sizeof(int)==1
implementación desizeof(int)==1
podría simplemente definir el sistema de archivos como vacío y de solo lectura. Entonces no habría forma de que una aplicación pudiera leer datos escritos por sí mismo, solo desde un dispositivo destdin
enstdin
que podría implementarse de modo que solo dé valores dechar
positivos que se ajusten aint
.
Editar (nuevamente): del C99 Rationale, 7.4:
EOF es tradicionalmente -1, pero puede ser cualquier número entero negativo y, por lo tanto, se puede distinguir de cualquier código de carácter válido .
Esto parece indicar que sizeof(int)
puede no ser 1, o al menos que esa era la intención del comité.
Creo que tienes razón. Tal implementación no puede distinguir un valor de char sin signo legítimo de EOF cuando se usa fgetc
/ fputc
en transmisiones binarias.
Si hay tales implementaciones ( este hilo parece sugerir que hay), no son estrictamente conformes. Es posible tener una implementación independiente con sizeof (int) == 1
.
Una implementación independiente (C99 4) solo necesita admitir las características de la biblioteca estándar como se especifica en estos encabezados: <float.h>, <iso646.h>, <limits.h>, <stdarg.h>, <stdbool. h>, <stddef.h> y <stdint.h>. (Note que no <stdio.h>). Independiente puede tener más sentido para un DSP u otro dispositivo integrado de todos modos.
El compilador de TI C55x que estoy usando tiene un carácter de 16 bits y de 16 bits, e incluye una biblioteca estándar. La biblioteca simplemente asume un conjunto de caracteres de ocho bits, por lo que cuando se interpreta como un carácter como char de valor> 255 no está definido; y cuando se escribe en un dispositivo de secuencia de 8 bits, se descartan los 8 bits más significativos: por ejemplo, cuando se escribe en el UART, solo los 8 bits más bajos se transfieren al registro de desplazamiento y a la salida.
Es posible que una implementación cumpla con los requisitos de interfaz para fgetc
y fputc
incluso si sizeof(int) == 1
.
La interfaz para fgetc
dice que devuelve el carácter leído como un unsigned char
convertido a int
. En ninguna parte dice que este valor no puede ser EOF
aunque la expectativa es claramente que las lecturas válidas "generalmente" devuelven valores positivos. Por supuesto, fgetc
devuelve EOF
en una falla de lectura o al final de la transmisión, pero en estos casos también se establece el indicador de error del archivo o el indicador de fin de archivo (respectivamente).
Del mismo modo, en ningún lugar dice que no puede pasar EOF
a fputc
siempre que coincida con el valor de un unsigned char
convertido a int
.
Obviamente, el programador tiene que tener mucho cuidado en tales plataformas. Esto podría no hacer una copia completa:
void Copy(FILE *out, FILE *in)
{
int c;
while((c = fgetc(in)) != EOF)
fputc(c, out);
}
En cambio, tendrías que hacer algo como (¡no probado!):
void Copy(FILE *out, FILE *in)
{
int c;
while((c = fgetc(in)) != EOF || (!feof(in) && !ferror(in)))
fputc(c, out);
}
Por supuesto, las plataformas en las que tendrá problemas reales son aquellas en las que sizeof(int) == 1
y la conversión de unsigned char
a int
no es una inyección. Creo que esto sería necesariamente el caso en las plataformas que usan signo y magnitud o complementos para la representación de los enteros con signo.
Estás asumiendo que el EOF no puede ser un personaje real en el juego de caracteres. Si permite esto, entonces sizeof (int) == 1 está bien.
No creo que el estándar C requiera directamente que EOF sea distinto de cualquier valor que pueda leerse en una transmisión. Al mismo tiempo, parece dar por sentado que así será. Algunas partes de la norma tienen requisitos contradictorios que dudo que se puedan cumplir si EOF es un valor que se puede leer de una transmisión.
Por ejemplo, considere ungetc
. Por un lado, la especificación dice (§7.19.7.11):
La función de ungetc empuja el carácter especificado por c (convertido a un carácter sin signo) de nuevo a la corriente de entrada apuntada por la corriente. Los caracteres rechazados serán devueltos por las lecturas posteriores en esa secuencia en el orden inverso al de su empuje. [...] Se garantiza un carácter de retroceso.
Por otro lado, también dice:
Si el valor de c es igual al de la macro EOF, la operación falla y la secuencia de entrada no cambia.
Entonces, si EOF es un valor que podría leerse de la transmisión, y (por ejemplo) leemos de la transmisión e inmediatamente usamos ungetc
para volver a poner EOF en la transmisión, obtenemos un enigma: la llamada está "garantizada". para tener éxito, pero también se requiere explícitamente que falle.
A menos que alguien pueda ver una manera de reconciliar estos requisitos, me quedan muchas dudas sobre si dicha implementación puede ser conforme.
En caso de que a alguien le N1548 , N1548 (el borrador actual del nuevo estándar C) conserva los mismos requisitos.
No estoy tan familiarizado con C99, pero no veo nada que diga que fgetc
debe producir toda la gama de valores de char
. La forma obvia de implementar stdio en un sistema de este tipo sería poner 8 bits en cada char
, independientemente de su capacidad. El requisito de EOF
es
EOF
que se expande a una expresión constante de enteros, con tipo int y un valor negativo, que es devuelto por varias funciones para indicar el fin de archivo, es decir, no más entrada de una secuencia
La situación es análoga a wchar_t
y wint_t
. En 7.24.1 / 2-3 que define wint_t
y WEOF
, la nota al pie 278 dice
wchar_t
ywint_t
pueden ser del mismo tipo entero.
lo que parece garantizar que la verificación de rango "suave" es suficiente para garantizar que *EOF
no esté en el conjunto de caracteres.
Editar:
Esto no permitiría las transmisiones binarias, ya que en tal caso se requiere que fputc
y fgetc
no realicen ninguna transformación. (7.19.2 / 3) Las transmisiones binarias no son opcionales; solo su distinción de las secuencias de texto es opcional. Por lo tanto, parece que esto hace que dicha implementación no cumpla. Sin embargo, sería perfectamente útil, siempre y cuando no intente escribir datos binarios fuera del rango de 8 bits.
Recuerdo esta misma pregunta en comp.lang.c hace unos 10 o 15 años. Al buscarlo, he encontrado una discusión más actual aquí:
http://groups.google.de/group/comp.lang.c/browse_thread/thread/9047fe9cc86e1c6a/cb362cbc90e017ac
Creo que hay dos hechos resultantes:
(a) Puede haber implementaciones donde la conformidad estricta no es posible. Por ejemplo, sizeof (int) == 1 con valores negativos o bits de relleno de un complemento o magnitud de signo en el tipo int, es decir, no todos los valores char sin signo se pueden convertir a un valor int válido.
(b) La expresión idiomática típica ((c=fgetc(in))!=EOF)
no es portátil (excepto para CHAR_BIT == 8), ya que no se requiere que EOF sea un valor separado.
¿No sería suficiente si un char
nominal que compartía un patrón de bits con EOF
se definiera como no sensorial?Si, por ejemplo, CHAR_BIT era 16 pero todos los valores permitidos ocupaban solo los 15 bits menos significativos (suponga un complemento 2s de la representación int de magnitud de signo). ¿O debe todo lo representable en un char
tener un significado como tal?Confieso que no sé
Claro, eso sería una bestia extraña, pero estamos dejando que nuestra imaginación vaya aquí, ¿verdad?
R .. me ha convencido de que esto no se mantendrá unido. Debido a que una implementación alojada debe implementar stdio.h
y si fwrite
es capaz de fgetc
enteros en el disco, entonces fgetc
podría devolver cualquier patrón de bits que encaje en un char
, y eso no debe interferir con la devolución de EOF. QED.