How to use write() system call to write integer/float to a file descriptor?

Issue

For example:

int main()
{
    int out_fd = open("output.txt", O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);

    int pid = getpid();

    if (out_fd != 1) {
        write(out_fd, &pid, sizeof(pid));
        write(out_fd, "\n", 1);
    }
    close(out_fd);
}

or

int out_fd = open("output.txt", O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);

float f = 89.2;
if (out_fd != 1) {
    write(out_fd, &f, sizeof(f));
    write(out_fd, "\n", 1);
}
close(out_fd);

both produces unexpected results (garbled text), like "ff�B "

Although both can be conveniently solved with dprintf(), but can someone give me the write() system call version to write integers/floats to a fd?

Thanks!

Solution

write will just write out plain sequences of bytes. When you’re writing out a "native" datatype like int, what’s getting written into the file are the bytes which bits in succession will make up that type, in the machines byte and bit order (search for "Big Endian vs Little Endian" on that).

What you’re expecting is a textual representation of the numbers written out. So the first thing you have to do is to format the binary representation of the value into a textual representation. Which is exactly what snprintf and the likes are doing. Once you’ve got the textual representation you can write out that using write.

If you want to do it without *printf, then at least for integers it’s straightforward enough to implement. Just recursively divide by the number base, writing out the remainder of the division at each step, until the number reaches zero, then reverse the string. The maximum number of digits to process is also straightforward to determine: It’s log_base(2**bits) = bits · log_base(2) = bits · log(2) / log(base).

#include <stddef.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <math.h>

char *int_to_string(int v, unsigned base)
{
    unsigned N_max = ceilf(sizeof(v)*CHAR_BIT * logf(2) / logf(base)) + 1;
    char *const buf = calloc(1, N_max);
    if( !buf ){ return NULL; }

    char *digit = buf;
    while( v ){
        div_t const d = div(v, base);
        *digit = ((9 >= d.rem) ? '0' : 'a') + d.rem;
        if( (v = d.quot) ){ ++digit; }
    }
    for(char *tigid = buf; tigid < digit; ++tigid, --digit ){
        char const t = *tigid;
        *tigid = *digit;
        *digit = t;        
    }
    return buf;
}

int main(int argc, char *argv[])
{
    char const *const v = int_to_string(1234567890, 10);
    write(1, v, strlen(v));
}

However if you want to format float values into strings… well, how to do that properly still is an area of active research, and you should look into what’s called "Dragon algorithms".

write itself however will do no data conversion for you whatsoever. It just takes whatever exists at the address and length you pass to it, and emit it to the file as-is.

Answered By – datenwolf

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published