6

我有一个函数,它将作为参数给出的指针重新分配给新大小。现在,问题在于 - 根据手册页 -realloc需要一个已由malloccalloc之前返回的指针。

如何确保调用者传递一个满足这些要求的指针?似乎没有内置的 C 机制(如类型限定符或其他东西)可以这样做。

现在,在我重组我的 API 之前(因为我认为现在的功能不够健壮) - 你能确认我没有错过任何东西吗?

提前致谢。

编辑: 一种解决方案显然是函数中使用 malloc 。问题在于调用者没有“看到”分配。因此,我需要在文档中明确说明他必须释放指针。这比期望他们提供一个 malloc 的指针(这意味着调用者必须释放它)更糟糕。

我真正想要的是在编译时阻止滥用的东西。那,还有一匹小马。;-)

4

11 回答 11

10

如何确保调用者传递一个满足这些要求的指针?

文档。

定义 API。

如果编写调用者的人拒绝遵循 API,事情就会崩溃。他们拒绝遵守你的规则,事情就崩溃了。他们期待什么?

于 2010-07-23T14:07:13.000 回答
4

归根结底,C 中的指针只不过是一个机器字,它可能指向也可能不指向进程内存中的重要数据,这些数据可能由 malloc 分配,也可能不分配。没有这样的信息附加到任何指针。

只需向 API 添加一个又大又胖的警告。如果文档清楚地说“永远不要传递这个不是 malloc'd 的函数指针”,并且有人仍然这样做并且得到错误/崩溃,这不是你的错 - 你无法在这里进行防御性编程。

于 2010-07-23T14:12:47.620 回答
2

您无法确定指针指向的区域是否已被[m|c]alloc();'d。您只能定义您的 API,并希望您的 API 用户遵循它。

自己(被调用者)分配内存是否令人望而却步?realloc(NULL, size);如果您受此约束,您仍然可以进行初始分配。

有关您的问题的更多信息会很好。

于 2010-07-23T14:10:02.727 回答
2

一种可能的方式。抽象它。

foo.c
#include "foo.h"
struct foo{
   ...
} ;

foo *newFoo(...)          
void resize(foo *f)      

foo.h

struct foo;
typedef struct foo;

caller.c

foo *myfoo;
myfoo = newFoo(..)
resize(myfoo);
于 2010-07-23T14:41:42.920 回答
2

用户应该如何首先获得这个 malloc 的指针?是不是有可能是你的API中的另一个函数获得的?否则,这对我来说听起来像是样板代码,在调用你的函数之前必须用 malloc 分配一块内存。

在你的情况下,我会尝试。让调用者通过我提供的函数获取有效指针并通过另一个函数释放它。更好的是,将它们全部包裹在一个不透明的结构中。

my_param_type my_param = init_param(....);
...
my_function_that_wants_malloc(.....,my_param);
...
free_param(my_param);

这在您的 API 中有意义吗?

拥有自己的类型,即使是最蹩脚的用户也很清楚,他必须通过预期的 init_param() 函数来获取它。

于 2010-07-23T15:18:30.347 回答
0

您可以在函数中维护一个静态指针并自己调用 realloc。返回静态指针。这样用户就不用担心分配或释放。当进程终止时,该变量将被自动释放。

请注意,如果 realloc 失败,它会返回一个空指针,但原始 malloc 的内存保持不变,这是内存泄漏的常见来源。

于 2010-07-23T14:12:07.963 回答
0

更改您的实现,以便您不使用 realloc。如果传入的缓冲区太小,只需 malloc 一个新的更大的缓冲区并将传入缓冲区的内容 memcpy 到它。这将以牺牲少量性能为代价来提高 API 的可用性。

于 2010-07-23T14:40:44.383 回答
0

如果您只有指针值,则没有(标准)方法可以确定该指针值是否由malloc(). 如果您对动态内存分配在您的平台上的工作方式有深入了解,那么您可以根据指针值做出有根据的猜测,但即使这样也不能保证您看到的东西实际上是malloc()相反的返回值到从那个偏移的值(例如,*ptr = malloc(10); foo(&ptr[5]);)。

一种可能值得或可能不值得努力的策略(IME,它不是)是将malloc(), realloc(), 和free()隐藏在某种跟踪分配的指针和大小的内存管理器后面。您的代码不会调用 ,而是调用realloc()内存管理器中的 resize 函数,如果传递给它的指针不在托管指针列表中,它将返回错误代码。

于 2010-07-23T14:52:27.890 回答
0

创建一个重命名的 void 指针的自定义数据类型。

typedef void* myPointerType;

malloc编写一个用户必须用来分配内存的分配函数(可以是一个简单的包装器)。

myPointerType myAllocateFunction (size_t size) {
    return (myPointerType)(malloc(size));
}

您还想制作一个匹配的“免费”功能。

现在,让您的函数(执行 的函数realloc)将myPointerType对象作为参数而不是通用指针。您可以将其转换回 avoid*以与 一起使用realloc。为了解决这个问题,用户必须手动将非malloced 指针强制转换为 a myPointerType,但您可以在文档中指定myPointerType不允许强制转换(因此,如果他们这样做并且他们的应用程序崩溃,那是因为他们误用了API)。

有更强大的方法可以强制执行此操作,但我不确定这是否值得麻烦。你不能完全保证 API 的安全(你会惊讶于这些天傻瓜的能力)。无论您最终实现什么,确保正确使用 API 的最佳方式是提供清晰、全面的文档。

对不起,小马只能靠你自己了。

于 2010-07-23T15:50:31.103 回答
0

如果您正在寻找编译时检查,您唯一能做的就是声明一些由“已批准”分配调用返回的新类型。我会建议类似:

typedef struct MEM_INFO {void *ptr; 整数分配;结构 *privateMemInfo priv;} ALLOCMEM[0];

privateMemInfo 将在您的 .c 文件中定义,而不是在标头中,从而在一定程度上保护其中的字段免受恶作剧。请注意,由于 ALLOCMEM 将是一个数组类型,因此 ptr 和 allocsize 将始终使用箭头运算符而不是点来访问。将 ALLOCMEM 作为参数的例程自然会得到一个指向 ALLOCMEM 的指针,允许它“很好地”执行重定位。因此,例如,可以使用:

  ALLOCMEM foo = {0};
  if (reallocate(foo,12345) >= 0) /* 成功了 */
于 2010-07-23T15:54:12.587 回答
0

因此,我需要在文档中明确说明他必须释放指针。这比期望他们提供一个 malloc 的指针(这意味着调用者必须释放它)更糟糕。

在 C 库中,这是一种常见的做法:

于 2010-07-23T16:19:54.647 回答