write(2)

System call

System call that hands bytes to a file descriptor (1 for stdout, 2 for stderr), with no buffering and no formatting. Returns the number of bytes written.

Synopsis
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);

Description

write asks the kernel to write count bytes, read from buf, to the descriptor fd. A descriptor is a small integer: 0 for standard input, 1 for standard output, 2 for standard error, then the ones returned by open, pipe or socket.

It is the call that sits underneath printf(3) and puts(3), without what they add. No buffer in your process: when write returns, the bytes are in the kernel's hands. No formatting: write knows nothing about strings or numbers, only bytes. To print an integer, you first have to turn it into digits yourself.

Return value

The number of bytes actually written, or -1 on error, with the cause in errno. That number can be smaller than count, for example when the disk is full or a signal interrupts the write partway through. A program that has to send everything calls write again with the rest, in a loop.

Pitfalls

  • count is a size in bytes, not a string length. write(1, s, sizeof s) on a char * sends 8 bytes on a 64-bit machine, the size of the pointer. For a string, use strlen(s).

  • write does not add a \n and does not stop at the '\0': write(1, "abc", 4) sends the null byte too.

  • Mixing write and printf on the same output scrambles the display order as soon as stdout is no longer a terminal, because printf keeps its text in a buffer. The demonstration is in printf prints nothing before a crash.

  • An accented character takes several bytes in UTF-8: strlen counts them correctly, a number written by hand easily gets it wrong.

Example

write.c
#include <string.h>#include <unistd.h>
int main(void){    const char *msg = "connection established\n";    ssize_t n;
    n = write(1, msg, strlen(msg));    if (n == -1)        return 1;    write(2, "done\n", 5);    return 0;}
Terminal
$ gcc -Wall -Wextra -g write.c -o write$ ./writeconnection establisheddone$ ./write > out.txtdone$ cat out.txtconnection established

The > redirection only affects descriptor 1: the message sent to descriptor 2 stays on the screen.

C

write_str

Write write_str, which sends a string to descriptor 1 with write, one character per call, without the terminating null byte.

Open the exercise

Now write it yourself.