Table of Contents
Input-output system calls in C | Create, Open, Close, Read, Write
System calls in C are requests made by a program to the operating system kernel for services it can’t access directly. These services go beyond input and output devices and include functions like process control, file management, memory management, and inter-process communication. In C programming, various functions, such as create, open, read, and write, are used for input/output system calls.
Important Terminology
What is the File Descriptor?
The file descriptor is basically an integer that would identify an open file of the process.
A file descriptor table is a collection of integer array indices where each index corresponds to a file descriptor. Each element in this table is a pointer to a file table entry. In an operating system, there is one unique file descriptor table for each process.
A file table entry is an in-memory structure representing an open file. It is created when a program requests to open a file. These entries maintain information about the file, including the current file position.
Standard File Descriptors: When a process starts, it automatically has three standard file descriptors open: 0, 1, and 2. These are often referred to as stdin (0), stdout (1), and stderr (2). By default, each of these descriptors points to a file table entry for a file named /dev/tty
.
/dev/tty: This is an in-memory surrogate for the terminal. In other words, it’s a representation in the computer’s memory that stands for the terminal device. The terminal, in this context, is a combination of a keyboard and a video screen where the user interacts with the system.
- Read from stdin (fd 0):
When you type on the keyboard, the program reads from standard input (stdin), linked to file descriptor 0, and saves it from the file named/dev/tty
. - Write to stdout (fd 1):
Output you see on the screen is written to standard output (stdout), associated with file descriptor 1, and comes from the file named/dev/tty
. - Write to stderr (fd 2):
Error messages you see on the screen are written to standard error (stderr), linked to file descriptor 2, and also come from the file named/dev/tty
.
Input/Output System Calls
There are 5 Input/Output system calls.
1. Create
The creat()
function in C is used to create a new empty file. It allows us to specify the permissions and the name of the file we want to create. This function is defined in the <unistd.h>
header file, and the flags used as arguments are defined in the <fcntl.h>
header file. The creat()
function is a system call for file creation in C programming.
Syntax of create() in C
int create(char *filename, mode_t mode);
Parameter
- filename:It refers to the name of the file which you want to create
- mode: It is the permissions of the new file.
Return Value
When creating or opening a file, the first unused file descriptor is often returned, starting with 3 (as 0, 1, and 2 are typically reserved for stdin, stdout, and stderr). If there’s an error, the function returns -1.
How C create() works in OS
- Create a new empty file on the disk.
- Use a file creation function, such as
creat()
oropen()
with appropriate flags, to create a new file on the disk.
2.Create a file table entry.
- The operating system creates an in-memory structure called a file table entry to represent the newly created file. This structure holds information about the file, such as the current file position.
3.Set the first unused file descriptor to point to the file table entry.
- The operating system assigns the next available file descriptor (starting from 3, as 0, 1, and 2 are often reserved for stdin, stdout, and stderr) to the newly created file. This file descriptor now points to the file table entry in memory.
4.Return the file descriptor used, -1 upon failure.
- If the file creation and descriptor assignment are successful, return the newly assigned file descriptor. Otherwise, return -1 to indicate an error.
In C, this process might involve using functions like creat()
, open()
, and checking the return values for success or failure.
2. C open
The open()
function in C is used to open a file for reading, writing, or both. It is also capable of creating the file if it does not exist. This function is defined in the <unistd.h>
header file, and the flags passed as arguments are defined in the <fcntl.h>
header file. When using open()
, you can specify flags to control the file opening mode, and it’s important to note that additional flags are needed to create a file if it doesn’t exist.
Syntax of open() in C
int open (const char* Path, int flags);
- Path: Specify the path to the file you want to open. Use an absolute path (starting with “/”) when not working in the same directory as the C source file. Use a relative path (just the file name with extension) when working in the same directory.
- Flags: Flags are used to specify how you want to open the file. You can choose from various flags based on your requirements.
Flags | Description |
---|---|
O_RDONLY | It will Open the file in read-only mode. |
O_WRONLY | It will Open the file in write-only mode. |
O_RDWR | It will Open the file in read and write mode. |
O_CREAT | It can Create a file if it doesn’t exist. |
O_EXCL | It can Prevent creation if it already exists. |
O_ APPEND | It will Open the file and places the cursor at the end of the contents. |
O_ASYNC | It will Enable input and output control by signal. |
O_CLOEXEC | It will Enable close-on-exec mode on the open file. |
O_NONBLOCK | It will Disable the blocking of the file opened. |
O_TMPFILE | Create an unnamed temporary file at the specified path. |
How C open() works in OS
- Find the existing file on the disk.
- This involves searching for and identifying the file you want to access. You can use the file’s path, either absolute or relative, depending on your current working directory.
2.Create a file table entry.
- The operating system creates an in-memory structure called a file table entry to represent the existing file. This structure contains information about the file, such as the current file position.
3.Set the first unused file descriptor to point to the file table entry.
- The operating system assigns the next available file descriptor (typically starting from 3) to the existing file. This file descriptor now points to the file table entry in memory.
4.Return the file descriptor used, -1 upon failure.
- If the file is successfully opened and a file descriptor is assigned, return the file descriptor. Otherwise, return -1 to indicate an error.
Example of C open()
/ C program to illustrate
// open system call
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
extern int errno;
int main()
{
// if file does not have in directory
// then file foo.txt is created.
int fd = open("foo.txt", O_RDONLY | O_CREAT);
printf("fd = %d\n", fd);
if (fd == -1) {
// print which type of error have in a code
printf("Error Number % d\n", errno);
// print program detail "Success or failure"
perror("Program");
}
return 0;
}
Output
fd = 3
3. C close
The close()
function in C is used to inform the operating system that you have finished using a file descriptor and want to close the associated file. This function is defined in the <unistd.h>
header file.
Syntax of close() in C
int close(int fd);
Parameter
- fd: It represents the File descriptor of the file that you want to close.
Return Value
- 0 on success.
- -1 on error.
How C close() works in the OS
- Destroy file table entry referenced by element fd:
- Ensure that no other process is pointing to the file table entry.
- Remove or destroy the file table entry associated with the specified file descriptor (fd).
- Set element fd of the file descriptor table to NULL:
- Update the file descriptor table, setting the entry corresponding to fd to NULL. This indicates that the file descriptor is no longer associated with any file.
Example 1: close() in C
// C program to illustrate close system Call
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
int fd1 = open("foo.txt", O_RDONLY);
if (fd1 < 0) {
perror("c1");
exit(1);
}
printf("opened the fd = % d\n", fd1);
// Using close system Call
if (close(fd1) < 0) {
perror("c1");
exit(1);
}
printf("closed the fd.\n");
}
Output
opened the fd = 3
closed the fd.
Example 2
// C program to illustrate close system Call
#include<stdio.h>
#include<fcntl.h>
int main()
{
// assume that foo.txt is already created
int fd1 = open("foo.txt", O_RDONLY, 0);
close(fd1);
// assume that baz.tzt is already created
int fd2 = open("baz.txt", O_RDONLY, 0);
printf("fd2 = % d\n", fd2);
exit(0);
}
Output
fd2 = 3
When the program starts, file descriptors 0, 1, and 2 are already used. So, the first available file descriptor is 3. After closing and setting them to NULL, the next open()
gets file descriptor 3. That’s why the output of this program is 3.
4. C read
The read()
function in C reads a specified number of bytes (cnt
) from the file associated with the file descriptor (fd
) into the memory area pointed to by buf
. A successful read()
also updates the access time for the file. This function is defined in the <unistd.h>
header file.
Syntax of read() in C
size_t read (int fd, void* buf, size_t cnt);
Parameters
- fd: This is the file descriptor of the file from which you want to read data.
- buf: The buffer is where the data will be read into. It’s a designated memory area.
- cnt: This represents the length of the buffer, specifying how much data you want to read.
Important Points
- buf: Make sure that
buf
points to a safe memory location and has enough space (at least as much ascnt
) to avoid any problems. - fd: Use a valid file descriptor from
open()
. Iffd
is not valid (NULL), reading will cause an error. - cnt: This is how many bytes you want to read. But, keep in mind, the actual number of bytes read may be less than what you asked for
#include <unistd.h>
int main()
{
int fd, sz;
char* c = (char*)calloc(100, sizeof(char));
fd = open("foo.txt", O_RDONLY);
if (fd < 0) {
perror("r1");
exit(1);
}
sz = read(fd, c, 10);
printf("called read(% d, c, 10). returned that"
" %d bytes were read.\n",
fd, sz);
c[sz] = '\0';
printf("Those bytes are as follows: % s\n", c);
return 0;
}
Output
called read(3, c, 10). returned that 10 bytes were read.
Those bytes are as follows: 0 0 0 foo.
5. C write
Writes cnt bytes from buf to the file or socket associated with fd. cnt should not be greater than INT_MAX (defined in the limits.h header file). If cnt is zero, write() simply returns 0 without attempting any other action. The write() is also defined inside <unistd.h> header file.
Syntax of write() in C
size_t write (int fd, void* buf, size_t cnt);
Parameters
- fd: It is referred as the file descriptor
- buf: It is the buffer to write data to.
- cnt: It is the length of the buffer.
Return Value
- It will returns the number of bytes written on success.
- It will return 0 on reaching the End of File.
- return -1 on error.
- return -1 on signal interrupts
Important Points about C write
- File Open: Make sure the file is opened for writing before using
write()
. - Buffer Size: Ensure that the size of
buf
is at least as large as specified bycnt
to prevent overflow. - Writing Bytes:
cnt
is the number of bytes you want to write. The return value is the actual number of bytes written, which might be less thancnt
if there are fewer bytes available. - Signal Interruption: If a signal interrupts the
write()
:- If no data is written, it returns -1 and sets an error code.
- If some data is written before the interruption, it returns the number of bytes written before being interrupted.
Example of write() in C
// C program to illustrate
// write system Call
#include<stdio.h>
#include <fcntl.h>
main()
{
int sz;
int fd = open("foo.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fd < 0)
{
perror("r1");
exit(1);
}
sz = write(fd, "hello skillvertex\n", strlen("hello skillvertex\n"));
printf("called write(% d, \"hello skillvertex\\n\", %d)."
" It returned %d\n", fd, strlen("hello skillvertex\n"), sz);
close(fd);
}
Output
called write(3, "hello skillvertex\n", 12). it returned 11
Hence, we can view the file foo.txt after running the code, you will get output a “hello skillvertex“. If foo.txt file already contains some content in it then the write a system call that can overwrite the content and all previous content will be deleted and only “hello skillvetex” content will have in the file.
Example: Print “hello world” from the program without using any printf function.
// C program to illustrate
// I/O system Calls
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int main(void)
{
int fd[2];
char buf1[12] = "hello world";
char buf2[12];
// assume foobar.txt is already created
fd[0] = open("foobar.txt", O_RDWR);
fd[1] = open("foobar.txt", O_RDWR);
write(fd[0], buf1, strlen(buf1));
write(1, buf2, read(fd[1], buf2, 12));
close(fd[0]);
close(fd[1]);
return 0;
}
Output
hello world
Whereas, buf1 array’s string will print “hello world” is first written into stdin fd[0] then after that this string will write into stdin to buf2 array. After that write into buf2 array to the stdout and print output “hello world“.
FAQ- Input-output system calls in C | Create, Open, Close, Read, Write
Q1. How to create open close read and write files in C?
Ans. fopen() – It will create a new file or open a existing file.
fclose() – f close() will close a file.
getc() – It can reads a character from a file.
putc() – It will writes a character to a file.
fscanf() – It will reads a set of data from a file.
fprintf() – It will writes a set of data to a file.
Q2. What does write () do in C?
Ans. write()
attempts to write a specified number of bytes from a buffer to a file associated with an open file descriptor.
Q3. What is input and output in C language?
Ans. In C, you can use input and output functions to work with strings. Two common functions are gets()
for reading strings and puts()
for writing strings in an unformatted way.
Hello, I’m Hridhya Manoj. I’m passionate about technology and its ever-evolving landscape. With a deep love for writing and a curious mind, I enjoy translating complex concepts into understandable, engaging content. Let’s explore the world of tech together