简体   繁体   English

结构初始化的C结构

[英]C struct of structs initialization

I'm a little confused about the best way to initialize complex structs (struct of struct) 我对初始化复杂结构的最佳方法有点困惑(struct结构)

I basically have a setup like this 我基本上有这样的设置

typedef struct {
    float x;
    float y;
} Vectorf;

typedef struct {
    Vectorf position;
    Vectorf direction;
    Vectorf velocity;
} Player;

What would be the best way to initialize a Player object? 什么是初始化Player对象的最佳方法?

Variant A 变式A.

Vectorf position = {1.0f, 1.0f};
Vectorf direction = {1.0f, 0.0f};
Vectorf velocity = {0.0f, 0.0f};

Player player = {position, direction, velocity};

Variant B 变体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);

Or even create a function like 甚至创建一个像这样的功能

Player *createPlayer(float px, float py...)
Player createPlayer(float px, float py...)

But inside these I would need Variant A or B again I guess. 但在这些内部,我想再次需要Variant A或B.

Is it just a matter of taste or are there benefits for either? 这仅仅是品味问题还是有益处?

I also have something like this 我也有类似的东西

typedef struct {
    int x;
    int y;
    Texture *texture;
    bool walkable;
} Tile;

typedef struct {
    int width;
    int height;
    Tile *tiles;
} Map;

Here a create function seems more reasonable, because I can pass actual map data. 这里的创建函数似乎更合理,因为我可以传递实际的地图数据。

Player player = {.position = {1.0f, 1.0f}, 
             .direction = {1.0f, 0.0f},
             .velocity = {0.0f, 0.0f}};

Note this won't work in C++. 请注意,这在C ++中不起作用。 Only in C. 只在C.

I think that answer should be depends on your needs , both ways of creating objects are OK. 我认为答案应该取决于你的需求 ,两种创建对象的方式都可以。

Sometimes you don't need to worry about allocation memory with malloc if you are going to use an object only a couple of times and you don't need that the objects "survives" when the function exits. 有时你不需要担心malloc分配内存,如果你只想使用一个对象几次,并且当函数退出时你不需要对象“幸存”。 So your variant A would be OK. 所以你的变种A就可以了。

Sometimes you want to create a lot of objects and store them in other data structures (lists, trees, etc), and you need the objects to "live" throughout the whole program. 有时您想要创建大量对象并将它们存储在其他数据结构(列表,树等)中,并且您需要在整个程序中“生存”对象。 In this case your variant B would be the better. 在这种情况下,您的变体B会更好。 AnT's answer shows you how you could save lines of code for initialization. AnT的答案向您展示了如何为初始化保存代码行。

The other time when I consider using malloc is when I know that the struct is very large and would consume lots of bytes for each object, so having a lot of them could potentially eat up all your stack. 另一次当我考虑使用malloc时,我知道结构非常大并且会为每个对象消耗大量的字节,因此有很多可能会占用你所有的堆栈。 In that case I'd rather have these large objects in the heap, and also handling with pointers is much cheaper than having to creates copies when calling function that do not take pointers. 在这种情况下,我宁愿在堆中使用这些大对象,并且使用指针处理也比在调用不带指针的函数时创建副本要便宜得多。

I also use malloc when I see the structs as classes and I want a clean API for creating, using and destryoing them. 当我将结构视为类时,我也使用malloc ,我想要一个干净的API来创建,使用和去除它们。 I always use prefix for the functions and I always have a create, init and free function for every object type, something like this: 我总是为函数使用前缀,我总是为每个对象类型都有一个create,init和free函数,如下所示:

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);
....

and the three first functions usually look like this: 并且三个第一函数通常如下所示:

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);
}

I think this gives you a very clear and easy API to use. 我认为这为您提供了一个非常简单易用的API。 I maintain a C library at work where I have at least 50+ of these structs, all with the same scheme, using them it's easy because they all behave like this: 我在工作中维护一个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

For Variant A 对于变体A.

Player player = { { 1., 1. }, { 1., 0. }, { 0., 0. } };

You can also use a tagged variant for better clarity and readability, as in @dev_null's answer. 您还可以使用带标记的变体以获得更好的清晰度和可读性,如@ dev_null的答案。

For Variant B compound literals will help you 对于变体B 复合文字将帮助您

Player *player = malloc(sizeof *player);

*player = (Player) { { 1., 1. }, { 1., 0. }, { 0., 0. } };

If you have a memdup -like functionality at your disposal, you can implement Variant B as an one-liner 如果您可以使用memdup的功能,则可以将Variant B实现为单行

/* Assuming `void *memdup(const void *src, size_t size);` */

Player *player = memdup(
  &(Player) { { 1., 1. }, { 1., 0. }, { 0., 0. } },
  sizeof *player);

Again, feel free to use a tagged version, if you like it better. 再次,如果您更喜欢它,请随意使用标记版本。

Compound literals allow you to mix-and-match your original approach and {} -based approach, if you for some reason decide that it is beneficial 复合文字允许您混合搭配原始方法和基于{}的方法,如果由于某种原因决定它是有益的

Player *player = malloc(sizeof *player);

player->position = (Vectorf) { 1., 1. };
player->direction = (Vectorf) { 1., 0. }; 
player->velocity = (Vectorf) { 0., 0. }; 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM