Estaba discutiendo sobre el problema sutil que puedes enfrentar cuando escribes en C, así que (por diversión) comencé a crear un código a prueba de balas que puede leer un entero de 32 bits desde la entrada estándar.
Escribí este código:
#include<stdint.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sysexits.h>
void flush_stdin()
{ int c;
while ((c = getchar()) != '\n' && c != EOF);
}
int32_t readInt32()
{
char line[13]; // -2147483648\n#include<stdint.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sysexits.h>
void flush_stdin()
{ int c;
while ((c = getchar()) != '\n' && c != EOF);
}
int32_t readInt32()
{
char line[13]; // -2147483648\n%pre%
int32_t n = 0;
if (fgets(line, sizeof(line), stdin)) {
if (sscanf(line, "%d", &n) == 1) {
if ((line[0] == '-' && n > 0) || (line[0] != '-' && n < 0)) {
fprintf(stderr, "Overflow detected\n");
exit(EX_DATAERR);
}
if (feof(stdin))
flush_stdin();
return n;
}
}
fprintf(stderr, "Error: wrong int32\n");
exit(EX_DATAERR);
}
int main()
{
int32_t r;
r = readInt32();
printf("read %d\n", r);
return 0;
}
int32_t n = 0;
if (fgets(line, sizeof(line), stdin)) {
if (sscanf(line, "%d", &n) == 1) {
if ((line[0] == '-' && n > 0) || (line[0] != '-' && n < 0)) {
fprintf(stderr, "Overflow detected\n");
exit(EX_DATAERR);
}
if (feof(stdin))
flush_stdin();
return n;
}
}
fprintf(stderr, "Error: wrong int32\n");
exit(EX_DATAERR);
}
int main()
{
int32_t r;
r = readInt32();
printf("read %d\n", r);
return 0;
}
¿Es realmente a prueba de balas como creo? ¿Tienes algunos consejos sobre este código?
El principal inconveniente es que trunca los primeros 13 bytes de su entrada, por lo que si proporciona algo como 000000000000001, lee 0.
EDITAR:
este código funciona como se espera solo si genera un ejecutable de 64 bits, pero la solución proporcionada por @Colin es mejor ...