结构初始化的C结构
C struct of structs initialization
我对初始化复杂结构的最佳方法有点困惑
(结构的结构)
我基本上有这样的设置
typedef struct {
float x;
float y;
} Vectorf;
typedef struct {
Vectorf position;
Vectorf direction;
Vectorf velocity;
} Player;
初始化 Player 对象的最佳方法是什么?
变体 A
Vectorf position = {1.0f, 1.0f};
Vectorf direction = {1.0f, 0.0f};
Vectorf velocity = {0.0f, 0.0f};
Player player = {position, direction, velocity};
变体 B
Player *player = malloc(sizeof(Player));
player->position.x = 1.0f;
player->position.y = 1.0f;
player->direction.x = 1.0f;
player->direction.y = 0.0f;
player->velocity.x = 0.0f;
player->velocity.y = 0.0f;
--- Stuff ---
free(player);
或者甚至创建一个像
这样的函数
Player *createPlayer(float px, float py...)
Player createPlayer(float px, float py...)
但我想在这些里面我会再次需要变体 A 或 B。
这只是口味问题还是两者都有好处?
我也有这样的东西
typedef struct {
int x;
int y;
Texture *texture;
bool walkable;
} Tile;
typedef struct {
int width;
int height;
Tile *tiles;
} Map;
这里创建一个函数似乎更合理,因为我可以传递实际的地图数据。
Player player = {.position = {1.0f, 1.0f},
.direction = {1.0f, 0.0f},
.velocity = {0.0f, 0.0f}};
请注意,这在 C++ 中不起作用。仅在 C.
对于变体 A
Player player = { { 1., 1. }, { 1., 0. }, { 0., 0. } };
您也可以使用标记的变体来提高清晰度和可读性,如@dev_null 的回答。
对于变体 B 复合文字 会帮助你
Player *player = malloc(sizeof *player);
*player = (Player) { { 1., 1. }, { 1., 0. }, { 0., 0. } };
如果您有类似 memdup
的功能供您使用,您可以将变体 B 实现为 one-liner
/* Assuming `void *memdup(const void *src, size_t size);` */
Player *player = memdup(
&(Player) { { 1., 1. }, { 1., 0. }, { 0., 0. } },
sizeof *player);
同样,如果您更喜欢,请随意使用带标签的版本。
复合文字允许您mix-and-match您的原始方法和基于{}
的方法,如果您出于某种原因认为它是有益的
Player *player = malloc(sizeof *player);
player->position = (Vectorf) { 1., 1. };
player->direction = (Vectorf) { 1., 0. };
player->velocity = (Vectorf) { 0., 0. };
我认为答案应该是取决于您的需要,两种创建方式
对象还可以。
有时您不需要担心 malloc
的内存分配问题,如果您
将只使用一个对象几次,你不需要
对象 "survives" 当函数退出时。所以你的变体 A 就可以了。
有时您想创建很多对象并将它们存储在其他数据结构(列表、树等)中,
并且您需要在整个程序中 "live" 对象。在这种情况下你的
变体 B 会更好。 AnT 的回答向您展示了如何节省线路
初始化代码。
我考虑使用malloc
的另一次是
当我知道该结构非常大并且会消耗大量字节时
每个对象,所以有很多对象可能会吃掉你所有的堆栈。在
在那种情况下,我宁愿将这些大对象放在堆中,并且还要处理
使用指针比调用时必须创建副本便宜得多
不接受指针的函数。
当我看到结构为 类 并且我想要一个干净的 API 时,我也使用 malloc
创建、使用和销毁它们。我总是为函数使用前缀,我
每种对象类型总是有一个创建、初始化和自由函数,比如
像这样:
typedef struct abc {
// lot's of members
} Abc;
Abc *abc_create(void);
int abc_init(Abc *abc); // always with default values
void abc_free(Abc *abc);
int abc_do_A(Abc *abc, int x);
int abc_do_B(Abc *abc, int y);
....
前三个函数通常如下所示:
Abc *abc_create(void)
{
Abc *abc = calloc(1, sizeof *abc);
if(abc == NULL)
return NULL;
if(abc_init(abc) == 1)
return abc;
free(abc);
return NULL;
}
int abc_init(Abc *abc)
{
if(abc == NULL)
return 0;
// initializations
...
return 1;
}
void abc_free(Abc *abc)
{
if(abc == NULL)
return;
// do free of other malloced
// members if present
free(abc);
}
我认为这让您非常清晰易用 API。我维护一个 C 库
在我至少有 50 多个这样的结构的工作中,所有这些结构都具有相同的方案,
使用它们很容易,因为它们的行为都是这样的:
Abc *abc = abc_create(1, 2, 3);
if(abc == NULL)
{
error handling
}
abc_do_A(abc, 12);
abc_do_A(abc, 11);
...
abc_free(abc); // when not needed anymore
我对初始化复杂结构的最佳方法有点困惑 (结构的结构)
我基本上有这样的设置
typedef struct {
float x;
float y;
} Vectorf;
typedef struct {
Vectorf position;
Vectorf direction;
Vectorf velocity;
} Player;
初始化 Player 对象的最佳方法是什么?
变体 A
Vectorf position = {1.0f, 1.0f};
Vectorf direction = {1.0f, 0.0f};
Vectorf velocity = {0.0f, 0.0f};
Player player = {position, direction, velocity};
变体 B
Player *player = malloc(sizeof(Player));
player->position.x = 1.0f;
player->position.y = 1.0f;
player->direction.x = 1.0f;
player->direction.y = 0.0f;
player->velocity.x = 0.0f;
player->velocity.y = 0.0f;
--- Stuff ---
free(player);
或者甚至创建一个像
这样的函数Player *createPlayer(float px, float py...)
Player createPlayer(float px, float py...)
但我想在这些里面我会再次需要变体 A 或 B。
这只是口味问题还是两者都有好处?
我也有这样的东西
typedef struct {
int x;
int y;
Texture *texture;
bool walkable;
} Tile;
typedef struct {
int width;
int height;
Tile *tiles;
} Map;
这里创建一个函数似乎更合理,因为我可以传递实际的地图数据。
Player player = {.position = {1.0f, 1.0f},
.direction = {1.0f, 0.0f},
.velocity = {0.0f, 0.0f}};
请注意,这在 C++ 中不起作用。仅在 C.
对于变体 A
Player player = { { 1., 1. }, { 1., 0. }, { 0., 0. } };
您也可以使用标记的变体来提高清晰度和可读性,如@dev_null 的回答。
对于变体 B 复合文字 会帮助你
Player *player = malloc(sizeof *player);
*player = (Player) { { 1., 1. }, { 1., 0. }, { 0., 0. } };
如果您有类似 memdup
的功能供您使用,您可以将变体 B 实现为 one-liner
/* Assuming `void *memdup(const void *src, size_t size);` */
Player *player = memdup(
&(Player) { { 1., 1. }, { 1., 0. }, { 0., 0. } },
sizeof *player);
同样,如果您更喜欢,请随意使用带标签的版本。
复合文字允许您mix-and-match您的原始方法和基于{}
的方法,如果您出于某种原因认为它是有益的
Player *player = malloc(sizeof *player);
player->position = (Vectorf) { 1., 1. };
player->direction = (Vectorf) { 1., 0. };
player->velocity = (Vectorf) { 0., 0. };
我认为答案应该是取决于您的需要,两种创建方式 对象还可以。
有时您不需要担心 malloc
的内存分配问题,如果您
将只使用一个对象几次,你不需要
对象 "survives" 当函数退出时。所以你的变体 A 就可以了。
有时您想创建很多对象并将它们存储在其他数据结构(列表、树等)中, 并且您需要在整个程序中 "live" 对象。在这种情况下你的 变体 B 会更好。 AnT 的回答向您展示了如何节省线路 初始化代码。
我考虑使用malloc
的另一次是
当我知道该结构非常大并且会消耗大量字节时
每个对象,所以有很多对象可能会吃掉你所有的堆栈。在
在那种情况下,我宁愿将这些大对象放在堆中,并且还要处理
使用指针比调用时必须创建副本便宜得多
不接受指针的函数。
当我看到结构为 类 并且我想要一个干净的 API 时,我也使用 malloc
创建、使用和销毁它们。我总是为函数使用前缀,我
每种对象类型总是有一个创建、初始化和自由函数,比如
像这样:
typedef struct abc {
// lot's of members
} Abc;
Abc *abc_create(void);
int abc_init(Abc *abc); // always with default values
void abc_free(Abc *abc);
int abc_do_A(Abc *abc, int x);
int abc_do_B(Abc *abc, int y);
....
前三个函数通常如下所示:
Abc *abc_create(void)
{
Abc *abc = calloc(1, sizeof *abc);
if(abc == NULL)
return NULL;
if(abc_init(abc) == 1)
return abc;
free(abc);
return NULL;
}
int abc_init(Abc *abc)
{
if(abc == NULL)
return 0;
// initializations
...
return 1;
}
void abc_free(Abc *abc)
{
if(abc == NULL)
return;
// do free of other malloced
// members if present
free(abc);
}
我认为这让您非常清晰易用 API。我维护一个 C 库 在我至少有 50 多个这样的结构的工作中,所有这些结构都具有相同的方案, 使用它们很容易,因为它们的行为都是这样的:
Abc *abc = abc_create(1, 2, 3);
if(abc == NULL)
{
error handling
}
abc_do_A(abc, 12);
abc_do_A(abc, 11);
...
abc_free(abc); // when not needed anymore