5

fwrite() is declared as this.

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

But the actual number of bytes written is just size * nmemb. So why not just specify the number of bytes? Why it is necessary to specify both size and nmemb? Thanks.

user1424739
  • 11,937
  • 17
  • 63
  • 152
  • 2
    One difference is that `fwrite` returns the number of whole objects successfully written. That seems minor, though, as it would be easily calculable from the number of byte written. – Eric Postpischil Feb 15 '19 at 14:11
  • The initial designers of the C library decided to do it like that, but just the number of bytes would have done the job as well. Or maybe it's because on early computers `int`s were 16 bits and the spec was: `fwrite(const void *ptr, int size, int nmemb, FILE *stream)` which would have allowed to write more than 64K at a time. Or maybe they wanted to have something slightly higher level. IMO having the two parameters doesn't provide much benefits today. – Jabberwocky Feb 15 '19 at 14:35

3 Answers3

0

There's no real reason.

The function is defined that way just because it is; more specifically in case of errors when not all the elements are written you've no guarantee that no partial element has been written or that the file pointer is in any specific location.

I normally just pass the element size as 1 and do the computation myself in the count parameter.

6502
  • 112,025
  • 15
  • 165
  • 265
0

I think it is subject to machine's endianness. fwrite() writes size * nmemb bytes. That is, call for the following two function results in same result.

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

Yet, the tricky point is for the following call, fwrite(ptr, 1, 1, buf); writes the byte at the lowest memory address. That is, it is the most significant byte on a big-endian machine. Otherwise, it is the least significant byte.

-1

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

As you can see in different fwrite realisation(not only at links above), the returned answer is return (size_t) written / size;. So on success you would have get returned value of nmemb.

Example:

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

Thanks to @Eric Postpischil for correcting my previous answer.

  • 1
    This is not correct. The output is byte-by-byte, not object-by-object. C 2018 7.21.8.2 2 says “For each object, `size` calls are made to the `fputc` function, taking the values (in order) from an array of `unsigned char` exactly overlaying the object. The file position indicator for the stream (if defined) is advanced by the number of characters successfully written. If an error occurs, the resulting value of the file position indicator for the stream is indeterminate.” – Eric Postpischil Feb 15 '19 at 15:14
  • 1
    Additionally, the code in this answer is broken. It uses `sizeof(arr)`, which is the size of a pointer `uint64_t *`, to specify the size of the objects to write, but the objects to write are the bytes allocated with `sizeof(uint64_t)`, which may be different. And we do not know the order in which the characters will be written, as they are assembled into a `uint64_t` with arithmetic, and a `uint64_t` could be represented with little-endian or big-endian. – Eric Postpischil Feb 15 '19 at 15:18
  • @Eric Postpischil My apologise. For the anwer i've check gcc code, but for embeded development we are using custom gcc and there fwrite works such as i have described above. Thanks for notice and checking my code. – Kurokawa Masato Feb 16 '19 at 17:59