3

I am trying to write into a file using the write() function (included in <unistd.h>). The program is simple: when running the executable, I type a message and then, the message and my user id (Linux UID) are saved into the file.

$ ./notetaker "Hello"

I was expecting that the following value could be saved into the file:

1000
Hello

There are two problems:

  • my file is being written in hexadecimal (when I open it using Sublime Text, all I can see are hexadecimal values)
  • the integer inserted representing my user id is not correct

This is the result that I'm getting when running cat notes.txt:

�
Hello

When I open the notes.txt file with Sublime Text, I can read the following data:

e803 0000 0a48 656c 6c6f 0a

The first 4 bytes are not equal to "1000".

Why is my file being saved with hexadecimal values? And why is the number incorrect?

This is my source code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>

void write_uid(const int);
void write_note(const int, void *);

int main(int argc, char *argv[])
{
    char *buffer = (char *) malloc(100);
    if(buffer == NULL) exit(0);
    strcpy(buffer, argv[1]);

    char *filename = (char *) malloc(50);
    if(filename == NULL) exit(0);
    strcpy(filename, "notes.txt");

    int file_descriptor = open(filename, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR);
    if(file_descriptor == -1) exit(0);

    write_uid(file_descriptor);
    write_note(file_descriptor, buffer);

    if(close(file_descriptor) == -1) exit(0);

    printf("Your note has been saved successfully. \n");
    free(buffer);
    free(filename);

    return 1;
}

void write_uid(const int file_descriptor)
{
    int current_user_id = getuid();
    int uid_write_result_code = write(file_descriptor, &current_user_id, sizeof(current_user_id));
    int new_line_write_result_code = write(file_descriptor, "\n", 1);

    if(uid_write_result_code < 0 || new_line_write_result_code < 0)
        exit(0);
}

void write_note(const int file_descriptor, void *buffer)
{
    int note_write_result_code = write(file_descriptor, buffer, strlen( (char *) buffer ));
    int new_line_write_result_code = write(file_descriptor, "\n", 1);

    if(note_write_result_code < 0 || new_line_write_result_code < 0) 
        exit(0);
}

I'm using an Ubuntu 14.04 Trusty Tahr (x64), and my GCC version is 4.8.4. Also, when compiling using the -Wall option, no warning is shown.

Suraj Jain
  • 4,463
  • 28
  • 39
Stanley Sathler
  • 368
  • 2
  • 12
  • 1
    Create a [mcve]. Also double check your tags. Does this question really have anything to do with C++? – eerorika Jan 16 '17 at 00:52
  • 4
    Your `write_uid` and `write_note` functions write numbers to the file, not representations of numbers in base 10. Your expectation that you would find the string "1000" in the file (a representation of the number one thousand in base ten) is unreasonable since you have no code to write base ten representations of numbers to the file. Quite possibly the most important thing for any programmer to understand is the difference between a number (like two, the number of hands I have) and representations of numbers, (like "two", an English word or "2" a decimal digit, which represent the number two). – David Schwartz Jan 16 '17 at 01:06
  • @user2079303 I'm sorry, my bad. I edited the code anyway following the "Minimal, Complete and Verifiable" requirement. @DavidSchwartz, thank you! After reading your comment carefully, I could see what I was doing wrong. As you said, the number itself (and not its representation) is right there: `e8 03 00 00`. I was trying to convert the number as it is, forgetting about the "little-endian" concept. When I converted the `3e8`, I could see the number. You really helped me. – Stanley Sathler Jan 16 '17 at 01:20
  • The computer did exactly what you told it to: it had some data, and you told it to write the data to a file, and it wrote the data to the file. What exactly did you expect it to do instead? – user253751 Jan 16 '17 at 02:16

2 Answers2

7

Your numerical value of 1000 is the first 4 bytes: e8 03 00 00.

Intel CPUs being little-endian, the bytes (not the nybbles) have to be reordered to read them in normal left-right order, so the value becomes 00 00 03 e8. Dropping the leading zeros leaves you 3e8 in hex, which is, indeed, 1000 in decimal.

Your problem here is that you are writing the bytes from current_user_id, which is a 32-bit integer, to your file character-by-character in memory order. If you want it to be human-readable as a number, you will have to convert it to a string representation using the function of your choice. The path of least resistance is probably to use fprintf() rather than write().

Emmet
  • 6,192
  • 26
  • 39
1

You have to format the result or other wise it will be written in raw binary. Use fprintf (file print formatted). Or if you're insesting on using write then format the integer using sprintf to get an equivalent string representation of that integer then save the string instead.

char str[20];
sprintf(str, "%i\n", current_user_id);
write(file_descriptor, str, strlen(str));
// no needto write \n, it's already included in str
ibrahim mahrir
  • 31,174
  • 5
  • 48
  • 73