对每个malloc调用进行错误检查时出现问题?

pkmbmrz7  于 2022-12-03  发布在  其他
关注(0)|答案(3)|浏览(122)

我正在用C语言编写一个简单的实用程序,我正在用STDERR编写打印错误消息的代码。
我有一个结构体,定义为:

struct arguments
{
    FILE *source;
    int modifier_value;
    int filesize;
};

我已经声明了一个指向上述结构体的指针,并为它分配了内存:

struct arguments *arg = NULL;
arg = malloc(sizeof(struct arguments));
if(arg == NULL)
{
    fprintf(stderr, "error: malloc - %s\n", strerror(errno));  //I know i could use perror as well, but I like the convention of using fprintf() for both stdout, stderr, and other file streams, just for symmetry
    return EXIT_FAILURE;
}

正如您所看到的,我只分配了足够存储struct arguments类型的一个对象的内存,并且我仍然在对它进行错误检查。
问题是我有很多指针指向一个对象的空间,对它们进行错误检查只会增加代码的数量,影响代码的可读性。
如果我忽略错误检查,仅仅因为我没有分配太多内存(我听说过分页,我认为如果我请求太多内存,系统会合并很多页面,在这种情况下出错的几率会很高,但对于64字节之类的内存请求,情况就不是这样了),这是一个“好做法”吗?

w8f9ii69

w8f9ii691#

如果我忽略错误检查只是因为我没有分配太多内存,这是一个“好做法”吗/“可以吗
不对报告错误的函数调用进行错误检查是糟糕的做法,除非你不关心调用是否成功。你 * 总是 * 关心malloc()是否成功,否则你不应该首先调用它。除非你检查你的malloc()调用是否成功,否则你不知道你是否分配了太多的内存。
问题是我有很多指针指向一个对象的空间,对它们进行错误检查只会增加代码的数量,影响代码的可读性。
首先,只在真正需要的地方使用动态分配。有些人似乎认为,只要需要指向某个对象的指针,就需要动态分配。但事实并非如此。如果执行动态分配,就需要指针,但在使用指针的地方,就不一定需要动态分配。通常情况下,静态或自动分配可以与address-of运算符(一元&)组合使用。例如:

{
    struct arguments arg = {0};
    init_arguments(&arg);
    do_something(&arg);
    // all done with arg
}

只有在以下情况下才需要动态分配:(i)在编译时不知道需要多少内存,或者(ii)需要一个对象,该对象的生存期超过了封闭其创建的最内层块的终止时间。
当您确实需要动态配置时,您可以使用宏或 Package 函数来减少样板程式码的数量。类似的作法也适用于执行其他成功检查。例如,使用类似下列的函数,而不要直接使用malloc()

void *checked_malloc(size_t size) {
    void *result = malloc(size);

    if (result == NULL && size != 0) {
        fputs("error: malloc failed -- aborting...\n", stderr);
        abort();
    }
    return result;
}
cnwbcb6i

cnwbcb6i2#

创建分配 Package 函数,以便始终轻松检查分配是否成功。
为了扩展@Weather Vane传递参数以标识调用者的想法,但在宏 Package 器中执行此操作。
my_malloc.h

#ifndef MY_MALLOC
#define MY_MALLOC(size) my_malloc((size), __FUNC__, __LINE__)
#include <stdlib.h>

// Return a valid allocation or don't return.
void *my_malloc(size_t size, const char *func, unsigned line);

#endif

my_malloc.c

#include "my_maloc.h"

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

void *my_malloc(size_t size, const char *func, unsigned line) {
  if (size == 0) {
    return NULL;
  }
  void *ptr = malloc(size);
  if (ptr == NULL) {
    fprintf(stderr, "Failed to allocate %zu bytes at \"%s()\", line %u\n",
        size, func, line);
    exit(EXIT_FAILURE);
  }
  return ptr;
}

user_code.c

#include "my_malloc.h"

...
  // No need to explicitly pass the function name, line number
  arg = MY_MALLOC(sizeof *arg * n);
  // Error checking not needed.

  ...
  free(arg);

我甚至会考虑一个匹配的MY_FREE,其中释放传递了指针和预期的大小。

ctrmrzij

ctrmrzij3#

如果有很多对象,可以立即为所有对象分配内存:

void *pvc;
pvc = malloc(how_many_for_all);

然后连续声明指向对象的指针,如下所示:

Obj1 *p1;
Obj2 *p2;
Obj3 *p3;
p1 = (Obj1)pvc;
p2 = (Obj2)(pvc + sizeof(Obj1));
p3 = (Obj3)(pvc + sizeof(Obj1) + sizeof(Obj2));

这是伪代码。编译器会发出警告,但这是可行的。

相关问题