`fwrite()` 函数中为什么需要同时使用参数 `size` 和 `nmemb`?其目的是什么?

5

fwrite()被声明为下面这样。

size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);

但实际写入的字节数只是size * nmemb。那么为什么不直接指定字节数呢?为什么需要同时指定size和nmemb?谢谢。


2
一个区别是fwrite返回成功写入的整个对象的数量。虽然这似乎并不重要,但可以很容易地从写入的字节数计算出来。 - Eric Postpischil
C库的最初设计者决定这样做,但只有字节数也可以完成任务。或许是因为早期计算机上的“int”是16位的,规范是:fwrite(const void *ptr, int size, int nmemb, FILE *stream),这将允许一次写入超过64K。或许他们想要更高级一些的东西。在我看来,今天拥有这两个参数并没有太多好处。 - Jabberwocky
3个回答

0

我认为这取决于机器的字节序。 fwrite() 写入 size * nmemb 字节。也就是说,调用以下两个函数会得到相同的结果。

fwrite(ptr, 2, 10, buf);
fwrite(ptr, 10,2, buf);

然而,棘手的问题在于以下调用:fwrite(ptr, 1, 1, buf);会将字节写入最低内存地址。也就是说,在大端机器上它是最高有效字节,否则它是最低有效字节。


0

没有真正的原因。

函数被定义成这样,只是因为它是这样的;更具体地说,在出现错误时,如果没有写入所有元素,则无法保证未写入任何部分元素或文件指针位于任何特定位置。

我通常只传递元素大小为1,并在count参数中自己进行计算。


-1

https://chromium.googlesource.com/chromiumos/third_party/glibc/+/cvs/libc-970216/stdio/fwrite.c

正如您在不同的fwrite实现中所看到的(不仅仅是上面的链接),返回的答案是return (size_t) written / size;。因此,在成功时,您将获得nmemb的返回值。

例如:

#include <stdlib.h>
#include <stdio.h>
#include <inttypes.h>

int main() {

    int num = 2;
    uint64_t *arr = malloc(num * sizeof(uint64_t));
    arr[0] = (uint64_t)'a' ^ (uint64_t)'b' << 8 ^ (uint64_t)'c' << 16;
    arr[1] = (uint64_t)'d' ^ (uint64_t)'e' << 8 ^ (uint64_t)'f' << 16;

    size_t writed_size = 0;
    writed_size = fwrite(arr, sizeof(arr), num, stdout);
    if (writed_size == num) {
        printf(" : Success\n");
    }

    writed_size = fwrite(arr, 1, sizeof(arr) * num, stdout);
    if (writed_size == sizeof(arr) * num) {
        printf(" : Success\n");
    }
    writed_size = fwrite(arr, sizeof(arr) * num, 1, stdout);
    if (writed_size == 1) {
        printf(" : Success\n");
    }

    free(arr);

    return 0;
}

感谢 @Eric Postpischil 更正我的先前答案。


1
这是不正确的。输出是逐字节而不是逐个对象的。C 2018 7.21.8.2第2节说:“对于每个对象,调用fputc函数size次,按顺序从正好覆盖对象的unsigned char数组中取值。流的文件位置指示器(如果定义)将按成功写入的字符数向前移动。如果发生错误,则流的文件位置指示器的结果值是不确定的。” - Eric Postpischil
1
此外,这个答案中的代码是有问题的。它使用了 sizeof(arr) 来指定要写入的对象的大小,而 sizeof(arr) 是一个指向 uint64_t * 的指针的大小,但要写入的对象是用 sizeof(uint64_t) 分配的字节,这可能是不同的。我们也不知道字符将被写入的顺序,因为它们被组合成一个 uint64_t 进行算术运算,并且一个 uint64_t 可以用小端或大端表示。 - Eric Postpischil
@Eric Postpischil,非常抱歉。对于答案,我已经检查了gcc代码,但是对于嵌入式开发,我们使用自定义的gcc,其中fwrite的工作方式就像我上面描述的那样。感谢您注意并检查我的代码。 - Kurokawa Masato

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接