getline()
turns out to be very useful when programmer wants to read a line from a text file in C. You might already get to use it. However, it's actually not a standard library function.
#include <stdio.h>
#include <stdlib.h>
void fclose_helper(FILE *fp) {
if (fclose(fp) != 0) {
fprintf(stderr, "Error on closing file\n");
exit(1);
}
return;
}
int main(int argc, char *argv[]) {
// sanity check
if (argc < 2) {
fprintf(stderr, "Usage: ./main <filename>\n");
exit(1);
}
// open file
FILE *fp = NULL;
if ((fp = fopen(argv[1], "r")) == NULL) {
fprintf(stderr, "Error on opening file %s\n", argv[1]);
exit(1);
}
// get a line
char *lineptr = NULL;
size_t alloc_size = 0;
ssize_t num_char = getline(&lineptr, &alloc_size, fp);
// print
if (num_char != -1) {
printf("%s", lineptr);
} else {
fprintf(stderr, "Error on reading file %s\n", argv[1]);
free(lineptr); // cannot swap order with next line
fclose_helper(fp);
exit(1);
}
// free resources
free(lineptr);
fclose_helper(fp);
return 0;
}
Then we compile and run the program.
$ cat input.txt
hello world
$ gcc main.c -Wall -Wextra -Werror -pedantic -o main
$ ./main input.txt
hello world
Everything works well. This is because the default C standard applied to the gcc
is gnu17
, as of the time writing this article. This is an extension provided by GNU GCC.
$ gcc --version
gcc (GCC) 14.2.1 20250110 (Red Hat 14.2.1-7)
Copyright (C) 2024 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
If we specify to use the strict C standard, compile error happens.
$ gcc main.c -Wall -Wextra -Werror -pedantic -std=c17 -o main
main.c: In function ‘main’:
main.c:29:9: error: unknown type name ‘ssize_t’; did you mean ‘size_t’?
29 | ssize_t num_char = getline(&lineptr, &alloc_size, fp);
| ^~~~~~~
| size_t
main.c:29:28: error: implicit declaration of function ‘getline’ [-Wimplicit-function-declaration]
29 | ssize_t num_char = getline(&lineptr, &alloc_size, fp);
| ^~~~~~~
If you have to use the strict standard, how to fix the issue? The man page of getline
tells us to define macro.
Feature Test Macro Requirements for glibc (see feature_test_macros(7)):
getline(), getdelim(): Since glibc 2.10: _POSIX_C_SOURCE >= 200809L Before glibc 2.10: _GNU_SOURCE
Note that you need to define the macro at the beginning of the file. Otherwise when preprocessor looks into stdio.h
, it won't be able to enable the desired features for you, because preprocessor processes source code files line by line.
#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdlib.h>
void fclose_helper(FILE *fp) {
if (fclose(fp) != 0) {
fprintf(stderr, "Error on closing file\n");
exit(1);
}
return;
}
int main(int argc, char *argv[]) {
// sanity check
if (argc < 2) {
fprintf(stderr, "Usage: ./main <filename>\n");
exit(1);
}
// open file
FILE *fp = NULL;
if ((fp = fopen(argv[1], "r")) == NULL) {
fprintf(stderr, "Error on opening file %s\n", argv[1]);
exit(1);
}
// get a line
char *lineptr = NULL;
size_t alloc_size = 0;
ssize_t num_char = getline(&lineptr, &alloc_size, fp);
// print
if (num_char != -1) {
printf("%s", lineptr);
} else {
fprintf(stderr, "Error on reading file %s\n", argv[1]);
free(lineptr); // cannot swap order with next line
fclose_helper(fp);
exit(1);
}
// free resources
free(lineptr);
fclose_helper(fp);
return 0;
}
Comments NOTHING