#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 works, but you have to set every member one by one by name.
Maker2 works, but still needs 2 lines and extra syntax.
Maker3 seems to work here and is less words, but it seems to cause memory leaks sometimes.
Maker4 also works, but I would have to make macros for all numbers of members, like ALLOC1, ALLOC2, ALLOC3, ALLOC4, and so on. Surely there is a less hacked together way than macros.
There is a nice syntax for the global scope:
Candle candle = {wickCount, color, scent};
Is there any way to allocate and set all members in a short syntax from inside a function without the values becoming destroyed when the function ends?
UPDATE I figured out a macro that works for any number of members:
#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);
But it is still not the cleanest and I would still not like to use a macro if there is a better build-in standard way.
CodePudding user response:
You can put your whole code in a macro and call it "short" then. You might want to learn about __VA_ARGS__ and variadic macros. Your code does not handle allocation errors.
#define ALLOCRET(TYPE, ...) \
TYPE *_tmp = malloc(sizeof(TYPE)); \
if (_tmp) \
*_tmp = (TYPE){ __VA_ARGS__ }; \
return _tmp;
Candle *maker5(void) {
ALLOCRET(Candle, wickCount, color, scent);
}
Subjective: Overall, maker3 is the most readable, thus would be preferred. Hiding stuff behind macro may make your code hard to maintain and unreadable. Mixing uppercase and lowercase similar names is confusing - Candle and candle. Consider using visually clearly distinct names to reduce bugs. Consider writing struct keyword when using a structure.
CodePudding user response:
Personally I would go mark3 but if you really love one-liners you could try the following macro:
#define DYNINIT(T, ...) ((T*)memcpy(malloc(sizeof(T)), &(T){ __VA_ARGS__ }, sizeof (T)))
...
Candle *maker5(void) {
return DYNINIT(Candle, wickCount, color, scent);
}
Or use it directly in main(), e.g.
Candle* candle = DYNINIT(Candle, .wick = 2, .color="brown");
The macro does following steps:
- Allocate memory for type
Twithmalloc(sizeof(T)) - Create a compound literal with an initializer take from variadic macro
(T){ __VA_ARGS__)
Passing macro parameters as the initializer solves problem of making a dedicated ALLOC-like macro for each type.
- copy compound literal to destination memory
memcpy(malloc(...), &(T){ ... }, sizeof (T))
Note that memcpy() returns the destination address
- Cast the
void*returned frommemcpyto pointer toTto ensure some type safety.
