What do you think of the following function to offer an alternative to fgets, looking for insights about portability, safety, readability and performance:
#include <stdio.h>
#include <errno.h>
int sc_gets(char *buf, int n)
{
int count = 0;
char c;
if (__glibc_unlikely(n <= 0))
return -1;
while (--n && (c = fgetc(stdin)) != '\n')
buf[count++] = c;
buf[count] = '0円';
return (count != 0 || errno != EAGAIN) ? count : -1;
}
#define BUFF_SIZE 10
int main (void) {
char buff[BUFF_SIZE];
sc_gets(buff, sizeof(buff)); // how to use
printf ("%s\n", buff);
return 0;
}
NB: I have already read fgets() alternative which was interesting but my code is different.
Second version thanks to the comments and vnp's insight:
#include <stdio.h>
#include <errno.h>
long sc_gets(char *buf, long n)
{
long count = 0;
char c;
while (--n && (c = fgetc(stdin)) != '\n') {
if (c == EOF)
break;
buf[count++] = c;
}
buf[count] = '0円';
return (count != 0 || errno != EAGAIN) ? count : -1;
}
#define BUFF_SIZE 1024
int main (void) {
char buff[BUFF_SIZE];
sc_gets(buff, sizeof(buff));
printf ("%s\n", buff);
return 0;
}
1 Answer 1
The function does not handle end-of-file correctly.
stdin
is just a stream, and could be closed like any other stream. For example, typeCtrl-D
. Orecho -n a | ./a.out a????????
Keep in mind that reading beyond end-of-file doesn't set
errno
.There is no reason to special-case
count == 0
.An IO error doesn't break the loop. If it happened, all the subsequent invocations of
fgets
would returnEOF
, and upon the loop termination thecount
will ben
.Pass the buffer size as
size_t
. This is whatsizeof
yields, and the buffers could be large enough for their size to overflow an integer.
-
\$\begingroup\$ Thanks a lot for your insight, please have a look at version 2 :) \$\endgroup\$Antonin GAVREL– Antonin GAVREL2021年03月28日 01:13:42 +00:00Commented Mar 28, 2021 at 1:13
__glibc_unlikely()
it is probably best to wrap them in a macro to provide alternatives for implementations that don't have them. \$\endgroup\$likely
/unlikely
but don't implement it will expand to white space. Implementations that don't understand it don't automatically do something special to support it. I could be wrong (does the language standard say something special)? \$\endgroup\$undefined reference to __glibc_unlikely'
andunresolved external symbol __glibc_unlikely
respectively. \$\endgroup\$