在C99 +中结合使用指定的初始化程序和malloc?

时间:2011-09-01 02:33:13

标签: c malloc c99 designated-initializer

是否有一种很好的方法可以将C99中的指定初始值设定项与malloc的结果相结合?

以下似乎有不必要的重复:

typedef struct {
   int a, b, c;
} Type;

Type *t = malloc(sizeof *t);
*t = (Type) {
    .a = 2,
    .b = 3,
    .c = 5,
};

可以从上面的代码中删除Type*t吗?

3 个答案:

答案 0 :(得分:5)

因为你问过;)C中有一个工具可以避免显式重复代码,宏。那说我没有办法不重复至少类型的名称。但是在C ++中他们也不能,所以C至少同样好:):

我看到的最简单的是

#define DESIGNATE_NEW(T)            \
  memcpy(malloc(sizeof(T)),         \
         &(T const){ __VA_ARGS__ }, \
         sizeof(T))

会给出

Type *t = DESIGNATE_NEW(Type,
    .a = 2,
    .b = 3,
    .c = 5,
);
这有几个好处。

  • 它正确初始化所有成员,即使在使用非结构的架构上也是如此 浮点类型或指针的0的标准表示。
  • 除了Keith'版本之外,它是“编码风格”可接受的,因为它只是一个看起来像初始化的表达式,任何人都应该直观地捕获第二个代码片段应该做的事情。

注意:观察宏中的const,如果编译器认为这是相关的,则允许折叠复合文字的几个实例。此外,还有一种方法可以使用一个变体,其中指示符列表是可选的,参见下面的P99。

缺点是memcpy,我会对作业感到高兴。其次,在使用结果之前没有检查malloc的失败,但是可能会遇到一些奇怪的问题,让代码很好地退出。

P99我的方式略有不同。我们总是有类型的初始化函数,比如

inline
Type* Type_init(Type* t, int a, int b, int c) {
  if (t) {
    *t = (Type const){ .a = a, .b = b, .c = c };
  }
  return t;
}

可以通过宏魔术为abc提供默认参数(如果省略它们)。然后你可以简单地使用像

这样的东西
Type *t = P99_NEW(Type, 1, 2, 3);

在您的应用程序代码中。这样做更好,因为它可以避免在对malloc的调用失败时对指针进行dereferrencing。另一方面,这会重新引入初始化程序的顺序,因此也不完美。

答案 1 :(得分:2)

您可以使用可变参数宏。我不会声称这是一个好主意,但它确实有效:

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

#define CREATE(type, ptr, ...) \
    type *ptr = malloc(sizeof *ptr); \
    if (ptr) *ptr = (type){__VA_ARGS__}

int main(void)
{
    typedef struct {
        int a, b, c;
    } Type;
    CREATE(Type, t, .a = 2, .b = 3, .c = 5);
    printf("t->a = %d, t->b = %d, t->c = %d\n", t->a, t->b, t->c);
    return 0;
}

请注意,我无法使用通常的do { ... } while (0)宏定义技巧(它会创建一个新范围,并且t不可见),所以你必须是小心你使用它的上下文。

就个人而言,我认为我对不必要的重复感到高兴。

答案 2 :(得分:1)

不,这是使用指定初始值设定项的唯一方法。如果没有(Type){},编译器就不知道如何验证内容。