【问题标题】:C, initialize struct without mallocC、不使用malloc初始化struct
【发布时间】:2012-08-19 22:55:46
【问题描述】:

我会避免使用 malloc 来初始化结构,并且我正在寻找使用 oo 样式(如果可能)设计 C 软件的最佳实践。

只有 C99,不是 C++

第一个问题,当使用像对象这样的结构时,什么是可取的? typedef 它的指针与否?

这些是我的测试(所有工作都使用 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);
}

我觉得这很好,但是隐藏了代码,而且可能有害,你觉得呢? I case 3,什么是最佳选择:宏还是构造函数?

【问题讨论】:

  • 示例 1 和 2 不是有效代码。您不能获取临时地址并期望它包含有效值。如果你想要一个堆栈分配的指针,请改用 alloca。
  • 2 有效,为什么说无效?
  • 因为你取的是临时值的地址,这是未定义的行为。
  • 万一2我不使用临时值的地址...
  • 我不会对名称不反映它是指针的指针进行类型定义。如果 Item_ptr 太长,我会使用 Item *。

标签: c oop constructor struct


【解决方案1】:

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

相反,我会将您的“new”和“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-&gt;text[4]将永远是0。 (更好的是使用符号常量而不是 5 并将其也用于 strncpy 调用。)

【讨论】:

    【解决方案2】:

    案例 3 是我经常看到并推荐的。将代码包装在构造函数中非常好——为什么隐藏代码会成为问题?事实上,这是一个特性——从实现中隐藏接口。另外,不要为此使用宏 - 这对于宏来说是一项过于复杂的任务,然而,宏通常是邪恶的。

    在我看来,方法 1 和 2 非常丑陋(事实证明,它们也是 UB)并且不可读。此外,案例 1 不是 const 正确的,要么使用案例 2(好吧,也不要使用它,因为它会调用未定义的行为)或将“文本”声明为 const char *。

    【讨论】:

    • 谢谢,在第 3 种情况下,使用宏是一种更有效的初始化结构的方法,因为我使用文字结构复合初始化,使用 ctor 我必须首先将所有结构数据初始化为 0(使用 {0} ) 并在设置它们之后,这是真的吗?再次感谢
    • @blow 要么效率不高,要么缺陷很小,不值得编写和维护这样的宏。
    • 在性能不佳且内存量极少的嵌入式设备中,您会选择哪一个?
    • 好的,谢谢,我会按照你建议的方向去做,但是我对我正在尝试做的事情有些怀疑,我认为我选择像OO这样的设计模式是错误的,但是对于这我可能会打开一个新线程。再次感谢。
    • @H2C03 例3中,main中的两个指针指向的数据在哪里?
    猜你喜欢
    • 1970-01-01
    • 2011-07-29
    • 2017-07-21
    • 2015-07-14
    • 1970-01-01
    • 2021-09-21
    • 2022-01-17
    • 2014-11-18
    • 1970-01-01
    相关资源
    最近更新 更多