【问题标题】:Does the order of arguments matter for these library functions?这些库函数的参数顺序是否重要?
【发布时间】:2021-02-13 14:36:16
【问题描述】:

考虑这些库函数:

void *calloc(size_t num, size_t size);
size_t fwrite(const void *ptr, size_t size, size_t count, FILE *stream);

我的问题是我是否可以安全地切换一些参数。这是:

calloc(1, 8);
fwrite(p, 1, 8, s);

和这个一样吗?

calloc(8, 1);
fwrite(p, 8, 1, s);

是的,我没有使用返回值。这不是重点。我的问题很简单,如果我切换元素数量的参数和元素大小的参数是否重要。可能有更多的库函数适用于此,所以不要仅限于我给出的两个示例。

【问题讨论】:

  • No for calloc 对于fwrite 是,因为它会影响返回值,但如果忽略它则不会,这是不应该的。
  • 来自我的 VC2008 文档:“calloc 函数为 num 个元素的数组分配存储空间,每个元素的长度为 size 个字节。”这意味着元素是连续的并且没有填充。那么这两个调用是一样的。

标签: c fwrite calloc


【解决方案1】:

calloc()freadfwrite() 都将在交换计数和大小参数的情况下尝试相同的工作。顺便说一下,fread/fwritecalloc 以不同的顺序指定这些参数:

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

虽然calloc() 没有区别,但转置fread()fwrite() 中的参数会影响返回值,即成功读取或写入的元素数。确保使用正确的值并将返回值与nmemb 参数(第三个参数)进行比较:

#include <stdio.h>

struct chunk {
    int a, b, c;
};

size_t copy_chunks(FILE *from, FILE *to) {
    struct chunk array[64];
    size_t total = 0, nread, nwritten;
    while ((nread = fread(array, sizeof(*array), 64)) != 0) {
        nwritten = fread(array, sizeof(*array), nread);
        total += nwritten;
        if (nwritten != nread) {
            fprintf(stderr, "write error: wrote %zu of %zu elements\n", nwritten, nread);
            break;
    }
    return total;
}

请注意,在上述写入错误的情况下,实际写入了多少字节是不确定的。

这是来自 C 标准的文本:

7.21.8.2 fwrite 函数

概要

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

fwrite 函数从ptr 指向的数组中,将大小由size 指定的nmemb 元素写入stream 指向的流。对于每个对象,对fputc 函数进行size 调用,从恰好覆盖对象的unsigned char 数组中获取值(按顺序)。流的文件位置指示器(如果已定义)按成功写入的字符数提前。如果发生错误,则流的文件位置指示符的结果值是不确定的。

退货

fwrite函数返回成功写入的元素个数,只有遇到写入错误才会小于nmemb。如果sizenmemb 为零,则fwrite 返回零并且流的状态保持不变。

如果您不关心返回值,那确实没有什么区别……但是忽略错误可能会有所不同,具体取决于意外情况的后果。还要考虑您的代码的后续读者,并通过使用正确的参数使他们更容易理解它的作用。

其他库函数采用void * 指针、大小和计数参数,如果您以错误的顺序传递它们,如果不是未定义,则行为会受到严重影响:

void *bsearch(const void *key, const void *base,
              size_t nmemb, size_t size,
              int (*compar)(const void *, const void *));

void qsort(void *base, size_t nmemb, size_t size,
           int (*compar)(const void *, const void *));

void *bsearch_s(const void *key, const void *base,
                rsize_t nmemb, rsize_t size,
                int (*compar)(const void *k, const void *y, void *context),
                void *context);
errno_t qsort_s(void *base, rsize_t nmemb, rsize_t size,
                int (*compar)(const void *x, const void *y, void *context),
                void *context);

【讨论】:

    【解决方案2】:

    size 指的是一个对象的大小,而num 指的是此类对象的数量。我不明白你怎么能互换它。例如 这个,

    fwrite(p, 1, 8, s); // Will return 8 if successful.
    

    pp + 8 将八个1 字节元素写入文件流s

    然而,这个,

    fwrite(p, 8, 1, s); // Will return 1 if successful.
    

    将单个 8 字节元素从 p 写入 p + 8 到文件流 s

    当我们处理可能包含不同数据的struct 对象时,差异是显而易见的。

    当我们写入网络流时,差异也很明显。

    calloc 的情况下,内存单元是连续的并不重要。

    【讨论】:

    • 我看不出这种差异如何“清晰可见”。流以完全相同的顺序接收完全相同数量的数据。
    • @PaulOgilvie:作者并不是说差异在流中清晰可见。它们意味着差异对正在考虑语义的我们来说是清晰可见的。区别在于fwrite(p, 1, 8, s) != fwrite(p, 8, 1, s),因为它们有不同的返回值。
    猜你喜欢
    • 1970-01-01
    • 2015-05-22
    • 1970-01-01
    • 2023-03-23
    • 2020-06-10
    • 2015-07-28
    • 2016-10-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多