C,初始化没有malloc的struct

时间:2012-08-19 22:55:47

标签: c oop constructor struct

我会避免使用malloc来初始化一个结构,而我正在寻找使用oo风格设计C软件的最佳实践(如果可能的话)。

仅限C99,而非C ++

第一个问题,使用类似对象的结构时最好的是什么?是否指定了它的指针?

这些是我的测试(所有工作都使用gcc编译器):

案例1

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct sItem{
    int n;
    char* text;
} oItem, *Item;

int main(int argc, char** argv) {
    Item i1=(&(oItem){.n=1, .text="A"});
    Item i2=(&(oItem){.n=100, .text="ABC"});
    printf("%d, %s, %d\n", i1->n, i1->text, sizeof(*i1)); // 1, "A", 8
    printf("%d, %s, %d\n", i2->n, i2->text, sizeof(*i2)); // 1, "ABC", 8
    return (EXIT_SUCCESS);
}

这有效,但我认为不应该因为文本未初始化为包含字符串。 这是一段无效的代码吗?

案例2

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct sItem{
    int n;
    char text[5];
} oItem, *Item;

int main(int argc, char** argv) {
    Item i1=(&(oItem){.n=1, .text="A"});
    Item i2=(&(oItem){.n=100, .text="ABC"});
    printf("%d, %s, %d\n", i1->n, i1->text, sizeof(*i1)); // 1, "A", 12
    printf("%d, %s, %d\n", i2->n, i2->text, sizeof(*i2)); // 1, "ABC", 12
    return (EXIT_SUCCESS);
}

这有效,我认为这是正确的,是吗?

案例3

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define Item_new(i, n, s) (&(oItem){0});Item_ctor(i, n, s);
#define Item_neww(i, x, s) (&(oItem){\
        .n=x,\
        .text=s\
})

typedef struct sItem{
    int n;
    char text[5];
} oItem, *Item;


void Item_ctor(Item i, int n, char* text){
    i->n=n;
    strcpy(i->text, text);
}

int main(int argc, char** argv) {
    Item i1=Item_new(i1, 10, "ABC");
    Item i2=Item_neww(i2, 10, "ABC");
    printf("%d, %s, %d\n", i1->n, i1->text, sizeof(*i1)); // 10, "ABC", 12
    printf("%d, %s, %d\n", i2->n, i2->text, sizeof(*i2)); // 10, "ABC", 12
    return (EXIT_SUCCESS);
}

我觉得这很好,但隐藏了代码,也许可能有害,你怎么看? 我的情况3,最好的选择是什么:宏或构造函数?

2 个答案:

答案 0 :(得分:2)

不要做3,包含不受保护的;的宏让我非常紧张。

相反,我会用以下

替换你的“新”和“ctor”
#define Item_new(i, n, s) Item_ctor(&(oItem){0}, n, s)

Item Item_ctor(Item i, int n, char* text){
    if (i) {
      i->n=n;
      strncpy(i->text, text, 4);
    }
    return i;
}

这并没有打破用户对Item_new的期望:一个真实的 像宏一样返回一个值。

并且ctor应该进行必要的检查并且永远不会覆盖内存,i->text[4]将永远是0。 (最好是使用符号常量而不是5,并将其用于strncpy调用。)

答案 1 :(得分:1)

案例3是我看到的,并且会推荐。在构造函数中包装代码非常好 - 为什么隐藏代码会有问题?实际上,这是一个功能 - 将接口隐藏在实现之外。另外,不要使用宏 - 对于宏来说这是一个太复杂的任务,然而,宏通常是邪恶的。

方法1和2非常难看(事实证明,它们也是UB)并且在我看来是不可读的。此外,情况1不是const正确的,或者使用情况2(好吧,不要因为它调用未定义的行为而使用它)或者将“text”声明为const char *