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;
}