【问题标题】:Data content, when read operation fails in C数据内容,当 C 中的读取操作失败时
【发布时间】:2020-10-03 12:00:12
【问题描述】:

关于 C lib 函数读取,是否有任何定义当读取操作失败时数据会发生什么(计数 = -1)?假设 'data' 仍然保持之前的值;如果当前的读取操作失败,它会被覆盖吗?在我当前的实现中,调试显示旧值仍然存在,但是有什么“官方”定义的吗? 考虑以下代码:

int8_t count = 0;
int fd = open(I2C_BUS, O_RDWR);

if (fd < 0) {
    fprintf(stderr, "Failed to open device: %s\n", strerror(errno));
    return(-1);
}
...
count = read(fd, data, length);
if (count < 0) {
    fprintf(stderr, "Failed to read device(%d): %s\n", devAddr, ::strerror(errno));
    close(fd);
    return(-1);

【问题讨论】:

  • 请提供minimal reproducible example 以证明您所指的内容。我不确定您指的是哪个read()。据我所知,C 本身并不知道。
  • 如果函数读取数据失败,应该用什么新数据覆盖缓冲区?如果函数告诉你没有读取数据,为什么要浪费时间用花哨的新内容填充缓冲区呢?你为什么要关心?
  • @Gerhardh:我想人们可以想象这样一种情况,内核已经将一堆数据复制到你的缓冲区中,但在返回之前,它得到了一些数据无效的指示,所以它返回-1。问题是这种行为是否合法。

标签: c linux file


【解决方案1】:

TL;DR - 它没有标准化,它取决于文件系统的实现。


要回答您的问题,我们应该先看看您致电read 时会发生什么。

libc 提供的大多数“基本”函数实际上是内核系统调用的包装。我们看一下libc的read的代码,在read.c找到:

/* Read NBYTES into BUF from FD.  Return the number read or -1.  */
ssize_t
__libc_read (int fd, void *buf, size_t nbytes)
{
  return SYSCALL_CANCEL (read, fd, buf, nbytes);
}
libc_hidden_def (__libc_read)
weak_alias (__libc_read, read)

如您所见,libc 的 read 实际上调用了 syscall read

SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
{
    struct fd f = fdget(fd);
    ssize_t ret = -EBADF;
    if (f.file) {
        loff_t pos = file_pos_read(f.file);
        ret = vfs_read(f.file, buf, count, &pos);
        file_pos_write(f.file, pos);
        fdput(f);
    }
    return ret;
}

系统调用read 然后调用vfs_read,它是VFS 的一部分(代表Virtual File System) . VFS 是文件系统的抽象层。每个文件系统都注册了一堆 VFS 知道要调用的回调函数。

例如,让我们看看尝试从 ext4 文件系统读取文件时调用的函数链:

 read()           ---> libc
   |
   |
 __libc_read()    ---> libc
   |
   |
 syscall_read()   ---> kernel; found in linux/fs/read_write.c
   |
   |
 vfs_read()       ---> kernel; found in linux/fs/read_write.c
   |
   |
 new_sync_read()  ---> kernel; found in linux/fs/read_write.c
   |
   |
 generic_file_read_iter() ---> ext4's read function; found in fs/ext/ext4
   |
   |

   ...

它一直持续到最后一个内部函数被调用。调用 libc 的read 函数得到的返回值是从上面的函数返回的。

但是,重要的是要说大多数 filsystems(包括 ext4!)最终会调用一些通用内核的函数,例如 mm/filemap.c 中的 do_generic_file_read 函数。 回到您的问题 - 这取决于文件系统选择实现read() 的方式,并且没有标准化


归根结底 - 大多数文件系统会在发生错误时以类似方式处理缓冲区,但您无法保证。实际上,您的数据可能会保持不变,因为没有理由对其进行更改。

作为建议,如果您想确切了解会发生什么,您可以随时参考内核的源代码 :)

最好的问候。

【讨论】:

    猜你喜欢
    • 2015-08-26
    • 1970-01-01
    • 1970-01-01
    • 2014-05-05
    • 1970-01-01
    • 1970-01-01
    • 2017-05-19
    • 1970-01-01
    • 2018-02-16
    相关资源
    最近更新 更多