简短的回答:没有好的方法。最好的办法是坚持让 API 返回调用者释放的对象。
长答案:这是一种替代方法,允许对不透明对象进行堆栈分配。有一些警告:
- 您需要知道实际对象的大小
- 您需要了解您的机器和工具包的对齐要求(一点点)
警告 1 可以通过使用实用程序函数来打印大小(不导出到用户 API)以及用于捕获错误的断言来处理。
警告 2 可以通过在用户可见定义中添加具有最严格对齐要求的类型的元素来处理(尽管它不必在同一个位置。)
保持对齐避免了使用@2501 的答案中使用的序列化的需要。
在下面的示例中,您可以忽略“// trivial implementation”注释下方的代码。他们只是提供一个完整的工作示例,但算法与 OP 无关。
地图.h
#include <stdlib.h>
#define MAP_ITER_SIZE 16
typedef struct {
void *p; // force alignment to match implementation
char space[MAP_ITER_SIZE-sizeof(void*)];
} map_iterator;
typedef struct map map;
map *map_new(void);
void map_iterator_init(map_iterator *iter, map *m);
int map_iterator_next(map_iterator *iter, int *p_key);
map_user.c
#include <stdlib.h>
#include <stdio.h>
#include "map.h"
int main(int argc, char * argv[])
{
map_iterator it;
int key;
map *m = map_new();
map_iterator_init(&it, m);
while (map_iterator_next(&it, &key)) {
printf("%d\n", key);
}
}
地图.c
#include <stdlib.h>
#include <assert.h>
#include "map.h"
#define INITIAL_KEY (-1)
struct map {
int key_count;
int first_key;
};
// Keep struct size consistent with MAP_ITER_SIZE in map.h
typedef struct {
map *m;
int cur_key;
} map_iterator_impl;
map *map_new(void) {
map *m = malloc(sizeof(struct map));
// trivial implementation for example only
m->key_count = 2;
m->first_key = 10;
}
void map_iterator_init(map_iterator *iter, map *m)
{
map_iterator_impl *iter_impl = (map_iterator_impl *)iter;
assert(sizeof(map_iterator) == sizeof(map_iterator_impl)); // optimizes out
// trivial implementation for example only
iter_impl->m = m;
iter_impl->cur_key = INITIAL_KEY; // not a valid key
}
int map_iterator_next(map_iterator *iter, int *p_key)
{
map_iterator_impl *iter_impl = (map_iterator_impl *)iter;
// trivial implementation for example only
if (iter_impl->cur_key == INITIAL_KEY) {
iter_impl->cur_key = iter_impl->m->first_key;
} else {
++iter_impl->cur_key;
}
if (iter_impl->cur_key - iter_impl->m->first_key >= iter_impl->m->key_count) {
return 0;
}
*p_key = iter_impl->cur_key;
return 1;
}
unsigned int get_impl_size()
{
return (unsigned int) sizeof(map_iterator_impl);
}
权威人士会反对这一点,他们会有很好的观点。主要论点是代码不可移植,除非跳过箍以使所有支持的(处理器,编译器)情况下的 SIZE 常量都正确。对于每种情况,您还需要知道哪种数据类型具有最大的对齐要求。