【问题标题】:C and write() function - File is being written in hexadecimal and written int value is not correctC 和 write() 函数 - 文件以十六进制写入并且写入的 int 值不正确
【发布时间】:2017-01-16 00:51:12
【问题描述】:

我正在尝试使用write() 函数(包含在<unistd.h> 中)写入文件。该程序很简单:在运行可执行文件时,我键入一条消息,然后将消息和我的用户 ID(Linux UID)保存到文件中。

$ ./notetaker "Hello"

我希望可以将以下值保存到文件中:

1000
Hello

有两个问题:

  • 我的文件是用十六进制编写的(当我使用 Sublime Text 打开它时,我只能看到十六进制值)
  • 插入的代表我的用户 ID 的整数不正确

这是我在运行cat notes.txt 时得到的结果:

�
Hello

当我使用 Sublime Text 打开 notes.txt 文件时,我可以读取以下数据:

e803 0000 0a48 656c 6c6f 0a

前 4 个字节不等于“1000”。

为什么我的文件是以十六进制值保存的?为什么数字不正确?

这是我的源代码:

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

我使用的是 Ubuntu 14.04 Trusty Tahr (x64),我的 GCC 版本是 4.8.4。此外,使用 -Wall 选项进行编译时,不会显示警告。

【问题讨论】:

  • 创建一个minimal reproducible example。还要仔细检查您的标签。这个问题真的和C++有关系吗?
  • 您的 write_uidwrite_note 函数将数字写入文件,而不是以 10 为底的数字表示。您希望在文件中找到字符串“1000”(表示以十为底的数字一千)是不合理的,因为您没有代码将数字的以十为底的表示形式写入文件。对于任何程序员来说,最重要的可能是数字(比如两个,我的手数)和数字表示之间的区别(比如“二”,一个英文单词或“2”一个十进制数字,代表数字二)。
  • @user2079303 对不起,我的错。我还是按照“最小、完整和可验证”的要求编辑了代码。 @DavidSchwartz,谢谢!仔细阅读您的评论后,我可以看到我做错了什么。正如你所说,数字本身(而不是它的代表)就在那里:e8 03 00 00。我试图按原样转换数字,忘记了“小端”概念。当我转换3e8 时,我可以看到数字。你真的帮了我。
  • 计算机完全按照您告诉它的操作:它有一些数据,您告诉它将数据写入文件,然后它将数据写入文件。您到底希望它做什么?

标签: c unistd.h


【解决方案1】:

您的数值 1000 是前 4 个字节:e8 03 00 00

Intel CPU 是 little-endian,bytes(不是 nybbles)必须重新排序才能以正常的左右顺序读取它们,因此值变为 00 00 03 e8。删除前导零会使您的 3e8 变成十六进制,实际上是十进制的 1000。

您的问题是您正在将字节从current_user_id(一个 32 位整数)按内存顺序逐个字符地写入文件。如果您希望它作为数字可读,则必须使用您选择的函数将其转换为字符串表示形式。阻力最小的路径可能是使用fprintf() 而不是write()

【讨论】:

    【解决方案2】:

    您必须格式化结果,否则它将被写入原始二进制文件。使用fprintffile print f格式化)。或者,如果您要使用 write,则使用 sprintf 格式化整数以获得该整数的等效字符串表示,然后保存该字符串。

    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-12-22
      • 2011-10-10
      • 2015-08-22
      • 2014-03-16
      • 2013-07-11
      • 2015-01-03
      • 1970-01-01
      • 2013-05-03
      相关资源
      最近更新 更多