我正在使用GBDK编写Gameboy ROM,它有一个不稳定的malloc版本,我无法正常工作。我也无法返回结构中的结构。这让我不得不尝试返回一个指针,这就是为什么我想知道是否有一种方法可以避免在返回结构指针时使用malloc?
我基本上想做的是,我希望能够写这样的东西:
create_struct(struct_name, char member_x, char member_y);
这是我使用malloc:编写的代码
struct point {
char member_x;
char member_y;
};
struct point *makepoint(char member_x, char member_y) {
struct point *temp = malloc(sizeof(struct point));
temp->member_x = member_x;
temp->member_y = member_y;
return temp;
};
有各种有效的方法来返回指针(指向结构或任何类型的对象),但返回指向在调用函数之前不存在的新对象的指针的唯一方法是使用malloc
、realloc
、calloc
、aligned_alloc
(C11)或一些实现定义的分配函数(例如POSIX系统上的mmap
等)。
返回有效指针的其他方法包括:
-
指向具有
static
存储持续时间的对象的指针。这样的对象只存在一个实例,所以这通常是一种糟糕的方式。 -
作为参数传递给函数的指针,用作存储结果的位置。这通常是一种很好的方法,因为您将获得存储的责任推卸给调用者。
-
从某种全局池中获得的指向对象的指针。这在嵌入式系统和低端游戏设备的游戏设计中可能是一种非常好的方法。
是否可以在不使用malloc的情况下返回指向结构的指针?
I从技术上讲,是的您可以将结构设为static
,这样它就可以在函数调用中幸存下来:
struct foo *bar()
{
static struct foo f = { 1, 2, 3 };
return &f;
}
但我怀疑你是否真的想这么做(由于这有有趣的副作用,请阅读static
关键字的含义)。你有几种不同的可能性:
II。C标准库采用的方法总是让调用者隐式地负责提供结构和管理内存。因此,函数不是返回指针,而是接受指向结构的指针并填充它:
void dostuff(struct foo *f)
{
foo->quirk = 42;
}
III。或者返回结构本身,它没有伤害,是吗(它甚至可以进行移动优化):
struct foo bar()
{
struct foo f = { 1, 2, 3 };
return f;
}
所以,选择你的毒药。
只需执行以下操作:
void makepoint(struct point *dest, char member_x, char member_y) {
dest->member_x = member_x; // you had these wrong in your code, by the way
dest->member_y = member_y;
}
该结构将需要在其他地方"分配"(可能在堆栈上是您的最佳选择)。
您可以将结构作为参数传递,并让函数初始化它:
struct point *makepoint(struct point *pt, char x, char y) {
pt->x = x;
pt->y = y;
return pt;
}
然后这样称呼它:
struct point pt;
makepoint(&pt, 'a', 'b');
但你也可以这样做:
struct point pt = { 'a', 'b' };
注意,在这种情况下(struct point
只占用2个字节),您可以返回struct point
而不是struct point *
,(这不应该使用大型结构)
#include <stdio.h>
struct point {
char member_x;
char member_y;
};
struct point makepoint(char member_x, char member_y)
{
struct point temp;
temp.member_x = member_x;
temp.member_y = member_y;
return temp;
}
int main(void)
{
struct point t = makepoint('a', 'b');
printf("%c %cn", t.member_x, t.member_y);
return 0;
}
如果无法修复malloc()
,那么您可能只想管理自己预先分配的点,并限制可以"创建"的点的数量。你需要稍微改变一下你的积分,以便于管理:
union free_point {
union free_point *next;
struct point data;
};
union free_point free_point_pool[MAX_POINTS];
union free_point *free_point_list;
struct point *makepoint(char member_x, char member_y) {
static int i;
union free_point *temp;
temp = 0;
if (i == MAX_POINTS) {
if (free_point_list) {
temp = free_point_list;
free_point_list = temp->next;
}
} else {
temp = free_point_pool + i++;
}
if (temp) {
temp->data.x = x;
temp->data.y = y;
}
return &temp->data;
};
然后,您不应该对makepoint()
返回的结果调用free()
,而应该创建一个新函数来将其放置在free_point_list
上。
void unmakepoint (struct point *p) {
union free_point *fp = (union free_point *)p;
if (fp) {
fp->next = free_point_list;
free_point_list = fp;
}
}
最简单的事情就是返回一个使用命名初始化器创建的结构,并在内联函数中这样做,这样就不会有任何开销:
static inline struct point makepoint(char x, char y) {
return (struct point) { .x = x, .y = y };
}
然后你可以这样称呼它:
struct point foo = makepoint(10, 20);
再简单不过了!