是否有一种简洁的语法来为结构指针分配和填充值(函数结束时不会被破坏)?

Is there a clean and short syntax to allocate and fill values for a struct pointer (that is not destroyed when function ends)?

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

#define ALLOC3(t, n, a, b, c) t* n = malloc(sizeof(t));\
memcpy(n, &((t){a, b, c}), sizeof(t));

int wickCount = 3;
char* color = "green";
char* scent = "Fresh Balsam";

typedef struct Candle_ {
  int wickCount;
  char* color;
  char* scent;
} Candle;

Candle* maker1 () {
  /* Imagine some code here that generates data,
  but for now, I will use hard-coded values */
  
  /* Create candle */
  Candle* candle = malloc(sizeof(Candle));
  candle->wickCount = wickCount;
  candle->color = color;
  candle->scent = scent;
  return candle;
}

Candle* maker2 () {
  Candle* candle = malloc(sizeof(Candle));
  memcpy(candle, &((Candle){wickCount, color, scent}), sizeof(Candle));
  return candle;
}

Candle* maker3 () {
  Candle* candle = malloc(sizeof(Candle));
  *candle = (Candle){wickCount, color, scent};
  return candle;
}

Candle* maker4 () {
  ALLOC3(Candle, candle, wickCount, color, scent);
  return candle;
}

int main () {
  Candle* candle = maker4();
  /* Do some random things to check for memory leaks.
  Let me know if there is a better way to do this. */
  int temp = 5;
  char* tempstr = "Some filler text...";
  printf("Filler text...\n");
  printf("%s\n", tempstr);
  printf("Filler text...\n");
  printf("==============\n");
  printf("Values:\n");
  /* Finally, print the values */
  printf("%d\n", candle->wickCount);
  printf("%s\n", candle->color);
  printf("%s\n", candle->scent);
  return 0;
}

Maker1 有效,但您必须按名称一一设置每个成员。

Maker2 有效,但仍需要 2 行和额外的语法。

Maker3这里好像能用,字少,但好像有时会造成内存泄露

Maker4 也可以,但我必须为所有数量的成员创建宏,例如 ALLOC1、ALLOC2、ALLOC3、ALLOC4 等等。肯定有比宏更少的组合方式。

全局范围有一个很好的语法:

Candle candle = {wickCount, color, scent};

有没有什么方法可以在函数内部以简短的语法分配和设置所有成员,而不会在函数结束时破坏值?

更新 我想出了一个适用于任意数量成员的宏:

#define ALLOC(s, v, p) s* p = malloc(sizeof(s));\
memcpy(p, &v, sizeof(s));

/* Then you can call it with this: */
ALLOC(Candle, ((Candle){wickCount, color, scent}), candle);

但它仍然不是最干净的,如果有更好的内置标准方法,我仍然不想使用宏。

您可以将整个代码放在一个宏中,然后将其称为“short”。您可能想了解 __VA_ARGS__ 和可变参数宏。您的代码不处理分配错误。

#define ALLOCRET(TYPE, ...) \
   TYPE *_tmp = malloc(sizeof(TYPE)); \
   if (_tmp) \
       *_tmp = (TYPE){ __VA_ARGS__ }; \
   return _tmp;

Candle *maker5(void) {
   ALLOCRET(Candle, wickCount, color, scent);
}

主观:总的来说,maker3最易读的,因此是首选。隐藏宏背后的东西可能会使您的代码难以维护且不可读。混合大写和小写的相似名称令人困惑 - Candlecandle。考虑使用视觉上明显不同的名称来减少错误。使用结构时考虑写 struct 关键字。

我个人会去 mark3 但如果你真的喜欢 one-liners 你可以试试下面的宏:

#define DYNINIT(T, ...) ((T*)memcpy(malloc(sizeof(T)), &(T){ __VA_ARGS__ }, sizeof (T)))
...

Candle *maker5(void) {
   return DYNINIT(Candle, wickCount, color, scent);
}

或者直接在main()中使用,例如

Candle* candle = DYNINIT(Candle, .wick = 2, .color="brown");

宏执行以下步骤:

  1. 为类型 Tmalloc(sizeof(T))
  2. 分配内存
  3. 使用可变参数宏中的初始值设定项创建复合文字
(T){ __VA_ARGS__)

将宏参数作为初始化程序传递,解决了为每种类型制作专用 ALLOC 类宏的问题。

  1. 将复合文字复制到目标内存
memcpy(malloc(...), &(T){ ... }, sizeof (T))

注意memcpy()returns目的地址

  1. 将从 memcpy 返回的 void* 转换为指向 T 的指针以确保某种类型安全。