I am new to C and using it to program a Nordic nrf52 chip. I believe my problem is a general C one though rather than application.
I am setting up an array of structs using macros predefined in the chip SDK. Using those macros in the array initialisation works, but doing element by element does not.
So, the following works:
nrf_twi_mngr_transfer_t transfers_1[2] = { \
NRF_TWI_MNGR_WRITE(MSBARO5X_0_ADDR , ®_addr[1], 1, NRF_TWI_MNGR_NO_STOP), \
NRF_TWI_MNGR_READ (MSBARO5X_0_ADDR , &p_buffer[0], sizeof(p_buffer), 0)
};
Where:
typedef struct {
uint8_t * p_data; ///< Pointer to the buffer holding the data.
uint8_t length; ///< Number of bytes to transfer.
uint8_t operation; ///< Device address combined with transfer direction.
uint8_t flags; ///< Transfer flags (see #ref NRF_TWI_MNGR_NO_STOP).
} nrf_twi_mngr_transfer_t;
NRF_TWI_WRITE and _READ are macros that use further macros, for example:
#define NRF_TWI_MNGR_WRITE(address, p_data, length, flags) \
NRF_TWI_MNGR_TRANSFER(NRF_TWI_MNGR_WRITE_OP(address), p_data, length, flags)
which uses
#define NRF_TWI_MNGR_WRITE_OP(address) (((address) << 1) | 0)
and
#define NRF_TWI_MNGR_TRANSFER(_operation, _p_data, _length, _flags) \
{ \
.p_data = (uint8_t *)(_p_data), \
.length = _length, \
.operation = _operation, \
.flags = _flags \
}
What I want to do is change individual items in this array, for example:
transfers_1[0] = NRF_TWI_MNGR_WRITE(MSBARO5X_0_ADDR , ®_addr[1], 1, NRF_TWI_MNGR_NO_STOP);
However when I do that, I get the error "expected an expression".
MSBARO5X_0_ADDR is also defined in a define statement:
#define MSBARO5X_0_ADDR 0x76
If I replace this in any of the above code with a variable, I get the same "expected an expression" error. I suspect the two problems I have are due to the same lack of understanding on my part. SO forgive me for combining the two in a single post.
So the questions are:
-Why am I getting this error?
-Is it possible to change individual items in my array, and if so how?
-Is it possible to use a variable in place of the MSBARO5X_ADDR, and if so how?
Many thanks!
Ultimately, the macro expands into a brace enclosed initializer. Such a thing is not an expression, so it cannot be used as the right hand side of plain assignment (assignment and initialization are different things). It will work as part of a larger initializer, but not the way you try to use it unmodified.
But all is not lost. The syntax of the initializer implies c99 support. So we can use a trick. Structure objects can be assigned to eachother. So we need only obtain an object from somewhere. We can use a compound literal in order to create said object:
transfers_1[0] = (nrf_twi_mngr_transfer_t)NRF_TWI_MNGR_WRITE(/*Your arguments*/);
If you define the value of a structure the moment you declare it, the compiler will infer the type of the structure from the declaration. So this here will compile:
struct coordinates {
int x;
int y;
};
struct coordinates origin = { 10, 20 }; // This is OK
But if you assign a value to a previously declared variable, the compiler cannot infer its type. This code won't compile:
struct coordinates origin;
origin = { 10, 20 }; // ERROR! The type of the rvalue is unknown!
The type is unknown, because two structures are not equivalent in C just because they have the same members. E.g. this is legal in C:
struct coordinates {
int x;
int y;
};
struct dayOfYear {
int day;
int month;
};
Now what would { 5, 8 } be? The coordinates (5/8) or the 5th of August? It could be both. All that he compiler knows is that it is a struct of type { int, int }. Yet this does not define a type in C. The following is possible in some languages but it's not possible in C:
struct dayOfYear date = { 2, 3 };
struct coordinates cords = date; // ERROR!
Despite the fact that both structures are of type { int, int }, for the compiler struct dayOfYear and struct coordinates are two completely distinct and unrelated data types.
If you want to declare a hardcoded struct value, you need to tell the compiler what kind of struct that is:
struct coordinates origin;
origin = (struct coordinates){ 10, 20 }; // This is OK
Your NRF_TWI_MNGR_TRANSFER defines a hardcoded struct but only when you use that in a definition the compiler knows the type. If you try to use it as an assignment, you need to cast to the correct type.
transfers_1[0] = (nrf_twi_mngr_transfer_t)NRF_TWI_MNGR_WRITE(MSBARO5X_0_ADDR , ®_addr[1], 1, NRF_TWI_MNGR_NO_STOP);
Which is not really a cast, even though it has the same syntax. In fact this is just telling the compiler how to interpret the following data.
Related
Given that there are multiple struct typedefs (all different) but with the same first element 'out' as in:
typedef struct myStructOneOfMany
{
uint8_t out;
//somestuff that is different
void* inPntr[33];
struct myStructOneOfMany *prev;
struct myStructOneOfMany *next;
}myStructOneOfMany;
how could one use a generic struct:
typedef struct OUT
{
uint8_t out;
}OUT;
with only the 1st element to access just the 1st element of all the different types?
assume:
myStructOneOfMany *currMyStructOneOfMany = //pointer to 1st in the linked list
I have tried:
uint8_t value = (struct OUT*)(currMyStructOneOfMany->inPntr[4])->out;
... along with other variations and I get nowhere.
Thanks!
EDIT:
As written in Jonathan Leffler's great comment - C11 §6.7.2.1 ¶15 says:
A pointer to a structure object, suitably converted, points to its initial member (or if that member is a bit-field, then to the unit in which it resides), and vice versa.
Which is why we either use a struct in the first element (matching padding and all), or a single variable / enum. I prefer using structs because they are easier to extend later on, if you want to add something.
Structs are interesting and complex animals, their field include compiler specific paddings and alignments.
Although very often the code will work fine by a simple matching of the top element, it isn't always the case when you're trying to use a common header with a number of fields (that would be undefined behavior due to padding concerns)... single elements are fine.
A classic way (that is also a compiler correct way) to implement "inheritance" in C would look something like this:
struct parent_s {
/* common attributes */
int object_type; /* for example */
};
struct child_s {
/* must be first element if you want pointers to be interchangeable. */
struct parent_s parent;
/*more stuff */
int my_unique_data;
}
Similar code is used in network address structures.
P.S.
This was a very quick and simplified answer, enough to get you started but not very accurate.
As you explore this you will discover techniques that allow you to place the common structures all over the place and have multiple inheritance when you need it.
I used to miss inheritance in C, but these days I love C better than many OO languages because it gives me more control over the memory structure and I can manage most inheritance features without the need to resort to virtual function tables (which I very rarely do).
EDIT:
Following #AjayBrahmakshatriya 's comment, I thought a quick casting example might be nice... So here's something I'm working on that uses the exact type of inheritance you're asking about (I just started this part of the code today, so it might be glitchy, I also didn't sleep for two days...):
/** Used to identify te type of the RESP object. */
enum resp_type_enum {
/** A String object (`resp_string_s`) that indicates an error. */
RESP_ERR = 0,
/** A simple flag object object (`resp_object_s`) for NULL. */
RESP_NULL,
/** A simple flag object object (`resp_object_s`) for OK. */
RESP_OK,
/** A Number object object (`resp_number_s`). */
RESP_NUMBER,
/** A String object (`resp_string_s`). */
RESP_STRING,
/** An Array object object (`resp_array_s`). */
RESP_ARRAY,
/** A specific Array object object (`resp_array_s`) for Pub/Sub semantics. */
RESP_PUBSUB,
};
/* This is the parent "class" / object */
typedef struct { enum resp_type_enum type; } resp_object_s;
/* an Array child class */
typedef struct {
enum resp_type_enum type;
size_t len;
size_t pos; /** allows simple iteration. */
resp_object_s *array[];
} resp_array_s;
/* a String child class */
typedef struct {
enum resp_type_enum type;
size_t len;
uint8_t string[];
} resp_string_s;
/* a Number child class */
typedef struct {
enum resp_type_enum type;
int64_t number;
} resp_number_s;
I wrote macros that allow me to easily cast from one type to another. They include error checks (by returning NULL if the types don't match:
#define resp_obj2arr(obj) \
((resp_array_s *)((obj)->type == RESP_ARRAY || (obj)->type == RESP_PUBSUB \
? (obj) \
: NULL))
#define resp_obj2str(obj) \
((resp_string_s *)((obj)->type == RESP_STRING || (obj)->type == RESP_ERR \
? (obj) \
: NULL))
#define resp_obj2num(obj) \
((resp_number_s *)((obj)->type == RESP_NUMBER ? (obj) : NULL))
This allows me to do use the macros to easily switch between the different "types".
switch (obj->type) {
case RESP_ERR:
safe_write1('-');
safe_write2((resp_obj2str(obj)->string), (resp_obj2str(obj)->len));
safe_write_eol();
break;
case RESP_NULL:
safe_write2("$-1\r\n", (resp_obj2str(obj)->len));
break;
case RESP_OK:
safe_write2("+OK\r\n", 5);
case RESP_ARRAY:
case RESP_PUBSUB:
safe_write1('*');
safe_write_i(resp_obj2arr(obj)->len);
safe_write_eol();
{
resp_array_s *a = resp_obj2arr(obj);
a->pos = a->len;
obj = NULL;
while (a->pos) {
a->pos--;
push_obj(a->array[a->pos], obj);
obj = a->array[a->pos];
}
}
// ...
}
Well it seems I over thought things.
The last comment above compiles and works !
uint8_t value = *(uint8_t *)(…some expression denoting a pointer to a structure with a uint8_t first member…);
I thought I had to make a generic struct similar to my several typedefs.
As Jonathan said ... no need to get fancy.
The pointer to the struct is also a pointer to the first element as long as you cast the pointer to point to the same type as the first element.
Thanks to Jonathan Leffler for pointing this out !!
PS: one thing that threw me was the additional * at the beginning.
I assumed the cast to (uint8_t*) was enough but I guess this just says "treat the right side after the cast as a pointer to type uint8_t.
Without the * before the cast ... 'value' would get the pointer value ... not the value that the pointer points to.
I am still between beginner and intermediate on C but making progress
Thanks to you all !!
I have typdef'd a struct, and immediately below this I've simultaneously declared and initialised the variables I want using the typedef'd struct.
When I try to compile the code, there are no error messages relating to 'hi_aud', but the rest of the structs bring up the error 'error: ";" expected'. The array also brings up this warning, plus 'error: "}" expected'.
I'm using Hi-Tech C compiler v., which uses the C90 ANSI C standard.
/* Due to C90, do not change order of vars in struct or else code will explode
*/
typedef struct alarm {
const uint_fast32_t pattern[];
const uint_fast8_t size;
void (*toggle)(void);
void (*off)(void);
bool on;
bool init;
uint_fast8_t pos;
uint_fast16_t start;
uint_fast8_t overflows;
};
static struct alarm hi_aud {
[108, 27, 108, 20, 108, 12, 108, 5],
sizeof(hi_aud.pattern) / sizeof(*hi_aud.pattern),
&sounder_toggle,
&sounder_off,
};
static struct alarm med_aud {
[255, 50, 50, 255],
sizeof(med_aud.pattern) / sizeof(*med_aud.pattern),
&sounder_toggle,
&sounder_off,
};
static struct alarm lo_aud {
[255],
sizeof(lo_aud.pattern) / sizeof(*lo_aud.pattern),
&sounder_toggle,
&sounder_off,
};
static struct alarm hi_vis {
[255],
sizeof(hi_vis.pattern) / sizeof(*hi_vis.pattern),
&hi_vis_toggle,
&hi_vis_off;
};
static struct alarm med_vis {
[255],
sizeof(med_vis.pattern) / sizeof(*med_vis.pattern),
&med_vis_toggle,
&med_vis_off,
};
static struct *alarms = {&hi_aud, &med_aud, &lo_aud, &hi_vis, &lo_vis};
static uint_fast8_t alarms_siz = sizeof(alarms) / sizeof(*alarms);
edit When I use the '{}' brackets to initialise the array, another error "error: no identifier in declaration" comes up. This does not happen when I use the '[]' brackets.
Inside a strcut's defintion the elements' defintions are separated by ; not be ,. not the issue :}
Prior to C99 the initialiser list may not end by ,.confused by C99 change for enums. Ending it with a ; is always wrong. And there needs to be a = between the variable and its initialiser.
To initialise a struct's array member use curly braces ({}), not brackets ([]).
const uint_fast32_t pattern[]; is not a complete array definition.
Use const uint_fast32_t pattern[MAX_SOMETHING]; instead.
The proper way to initialize an array is with curly-brackets, not square brackets:
static struct alarm hi_aud = {
{108, 27, 108, 20, 108, 12, 108, 5}, /* Initialize "pattern") */
sizeof(hi_aud.pattern) / sizeof(*hi_aud.pattern), /* Initialize "size" */
Assuming you already declared struct alarm properly (and you didn't quite get it, because you missed the second part of the typedef):
Your code is:
static - This variable will have file-local scope.
struct alarm - The type of the variable.
hi_aud - The name of the variable
{...} - The structure initializers
You should also have an = between your variable at the structure initializers.
Addendum:
As others have pointed out, your code is a mess.
You did not complete a typedef.
You seem to be using variable length arrays in a language which does not support them
Your VLAs are in the middle of a structure which has a comment that says the structure may "explode".
In initializing structures, you're missing an = sign
You are not initializing arrays properly.
Your array sizes are all different.
You have trailing commas and misplaced semi colons, etc, etc.
In general, Write a TINY amount of code first, compile it, debug it.
Then add on a little bit more, compile it and debug it.
Repeat.
Do NOT write several pages of junk, then look on in wonder as it doesn't work.
Towards that end, lets fix your first typedef:
Typedef works with 2-elements, The TYPE, and the new NAME for the type:
typedef {existing element} {new name};
You only put in the first half.
You want:
typedef struct alarm { /* All the structure elements */ } alarm_t;
This makes a new type alarm_t.
After that, you tried to make the first element of the structure an array of undefined size. C allows flexible array members, but ONLY as the very last element of a struct, and those are tricky to use. So I'm going to make your array a fixed size:
typedef struct alarm {
const uint_fast32_t pattern[10]; /* Fixed Size */
const uint_fast8_t size;
void (*toggle)(void);
void (*off)(void);
bool on;
bool init;
uint_fast8_t pos;
uint_fast16_t start;
uint_fast8_t overflows;
} alarm_t;
The syntax for typedef for a struct is:
struct <optional struct name> {
struct fields...
} <typedef name>;
You haven't supplied any typedef name.
Suppose I have structure I'm using to model various packet formats:
#define MaxPacket 20
typedef struct {
u8 packetLength;
union {
u8 bytes[MaxPacket];
struct {
u16 field1;
u16 field2;
u16 field3;
} format1;
struct {
double value1;
double value2;
} format2;
};
} Packet;
I can expect that sizeof(Packet) will be 21. But is there any way to do something like:
sizeof(Packet.format2)
? I've tried that, but the compiler is not happy. Obviously, I could pull the format1 out as a separate typedef and then I could sizeof(format1). But I'm curious if I have to through all of that. I like the hierarchical composition of the formats. This is with gcc on an 8bit processor.
I'm equally interested if there's a way to use the nested type. IF I have to do a lot of
aPacketPointer->format2.value1; // not so onerous, but if the nesting gets deeper...
Then sometimes it would be nice to do:
Packet.format2 *formatPtr = &aPacketPointer->format2;
formatPtr->value2; // etc
Again, refactoring into a bunch of preceding typedefs would solve this problem, but then I lose the nice namespacing effect of the nested dotted references.
For something that will work even in C90, you can use a macro modeled on your toolchain's offsetof() macro:
#define sizeof_field(s,m) (sizeof((((s*)0)->m)))
Adjust it accordingly if your toolchain's offsetof() macro isn't based on casting 0 to a pointer to the structure's type.
When I use it like so:
std::cout << sizeof_field(Packet,format1) << std::endl;
std::cout << sizeof_field(Packet,format2) << std::endl;
I get the output:
6
16
For your second question, if you're willing to rely on GCC's typeof extension you can create a similar macro for declaring pointers to your nested anonymous structs:
#define typeof_field(s,m) typeof(((s*)0)->m)
...
typeof_field(Packet,format2)* f2 = &foo.format2;
To be honest, I find that construct pretty ugly, but it might still be better than other options you have available.
GCC documents that the "operand of typeof is evaluated for its side effects if and only if it is an expression of variably modified type or the name of such a type", so the apparent null pointer deference should not result in undefined behavior when a variable length array is not involved.
Using C11 or C99, create a dummy compound literal and seek its size.
printf("%zu\n", sizeof( ((Packet){ 0, { "" }}).format2 ));
Output
16
You can just give those nested structs a name, no need for a typedef. Like this:
typedef struct {
u8 packetLength;
union {
u8 bytes[MaxPacket];
struct myformat1 {
u16 field1;
u16 field2;
u16 field3;
} format1;
struct myformat2 {
double value1;
double value2;
} format2;
};
} Packet;
Then you can write e.g. sizeof(struct myformat1), declare variables of that type, etc.
You could also add a typedef afterwards, e.g.
typedef struct myformat1 myformat1;
I'm trying to write a macro in C (alas, not C++) in a way to trap certain errors, in particular if I pass a name of the wrong type.
For example, with
typedef int APLNELM;
typedef int APLRANK;
#define IsScalar(a) ((a) == 0)
APLNELM AplNelm = 0;
APLRANK AplRank = 0;
Calling IsScalar (AplRank) is correct because Scalar is a Rank concept, but IsScalar (AplNelm) is wrong because Scalar is not a # elements concept.
Can some clever person find a way to write the IsScalar macro such that it checks the type of the name passed to it to ensure that it is of type APLRANK? Feel free to rewrite the original example in any equivalent way if that provides a solution.
If these are the only two types that will ever be passed into the isScalar macro, then you could do something like this:
#include <stdio.h>
struct APLNELM {
int nelm;
char a[1];
};
struct APLRANK {
int rank;
char a[2];
};
#define isScalar(b) (sizeof b.a == 2)
int main(void) {
// your code goes here
struct APLNELM temp1;
struct APLRANK temp2;
printf("%d\n", isScalar(temp1));
printf("%d\n", isScalar(temp2));
return 0;
}
The output of this code is
0
1
This will work, but I highly suggest you don't use it as it wouldn't be super maintainable:
typedef int APLNELM;
typedef int APLRANK;
typedef unsigned int TYPETRAITS;
#define TRAIT_SCALAR 0x1
#define TYPETRAITS_APLNELM TRAIT_SCALAR /*whatever else you want, up to 32 traits*/
#define TYPETRAITS_APLRANK 0/*whatever else you want, up to 32 traits*/
#define GET_TYPE_TRAITS(X) TYPETRAITS_##X
#define IS_SCALAR(X) (X & TRAIT_SCALAR)
#define IS_TYPE_SCALAR(X) IS_SCALAR(GET_TYPE_TRAITS(X))
int main()
{
const int aplnelm_traints = GET_TYPE_TRAITS(APLNELM);
const int aplrang_traints = GET_TYPE_TRAITS(APLRANK);
const bool is_aplnelm_scalar = IS_TYPE_SCALAR(APLNELM);
const bool is_aplrang_scalar = IS_TYPE_SCALAR(APLNELM);
}
I gived up with following code (requires GNU extensions: typeof and Statement Exprs):
#include <stdio.h>
typedef int APLNELM;
typedef int APLRANK;
#define IsScalar(a) \
({ \
/* Override typedefs in block scope */ \
typedef char APLNELM; \
typedef int APLRANK; \
/* Create variable with typeof(a) type; \
* then compare it by sizeof with APLNELM */ \
typeof(a) b; sizeof b == sizeof(APLNELM); \
})
int main(void)
{
APLNELM a = 5;
APLRANK b = 5;
printf("IsScalar: %d\n", IsScalar(a) ? 1 : 0);
printf("IsScalar: %d\n", IsScalar(b) ? 1 : 0);
return 0;
}
The thing is that typeof(a) is actually not replaced by APLNELM or APLRANK. C is not dynamic language, I agree that struct concept would be better suited for such differentiation.
If you want to define two integer types that are different, the straight typedef approach fails, because typedef creates synonyms for the same type, never creates new types.
There is a manner to create different integer types, but even in this case, there is no way to "detect" them through their values.
For example, observe this code:
enum myint1_e {min1 = -32767, max1 = 32767};
enum myint2_e {min2 = -32767, max2 = 32767};
typedef enum myint1_e integer1_t;
typedef enum myint2_e integer2_t;
integer1_t x1 = 0;
integer2_t x2 = 0;
Now, the two types enum myint1_t and enum myint2_t are different integer types.
See C11: 6.7.2.3.(par.5):
Two declarations of [...] enumerated types which are in different scopes or use different tags declare distinct types.
So, their typedef-ed versions are, too, different.
Thus, the variables x1 and x2 have different types.
The integer value 0 can be assigned to both variables.
Now, if you want to check that the type of a variable is the one that you want, you can try doing that:
#define VERIFY_INT1TYPE(a) ((integer1_t*)(0) == (&a))
But this method only offers a Warning message, and not the "comparisson with value false" that you expected.
Explanation: Although the integer types are, in some way, interchangeable in assignment operations, on the other hand their "pointer to" versions are always different types. Thus, a sentence like x1 == x2 has not any problem at all, but the comparisson of a value of two different pointer types will raise a warning message.
Remark: The expression (integer1_t*)(0) is the NULL pointer cast to type integer1_t*.
Example:
VERIFY_INT1TYPE(x2);
This example raise a warning message when I compiled with GCC.
One possibility is to wrap the integer in a one-field struct, to enforce strong typing. To avoid the final production code being suboptimal, compile twice with different macro definitions; once with structs to detect errors, once without structs for optimal code.
#ifdef STRONG_TYPING
#define TYPE(basetype, field) struct { basetype field; }
#define INITIALIZER(value) {(value)}
#define AS_BASETYPE(field, value) ((value).field)
#else
#define TYPE(basetype, field) basetype
#define INITIALIZER(value) (value)
#define AS_BASETYPE(field, value) (value)
#endif
typedef TYPE(int, alpnelm) APLNELM;
typedef TYPE(int, alprank) APLRANK;
#define IsScalar(a) (AS_BASETYPE(aplrank, a) == 0)
With STRONG_TYPING defined, IsScalar(SomeAplNelm) will give a compiler error. Without STRONG_TYPING, the overhead of structs will be completely gone. Naturally, all modules must to be compiled with the same definition before linking, or your executable is likely to crash.
In your program code, you will have to apply some discipline when it comes to using the macros. Declaration example:
APLNELM MyAplNelm1;
APLNELM MyAplNelm2 = INITIALIZER(0);
Assignment:
AS_BASETYPE(aplnelm, MyAplNelm1) = 0;
AS_BASETYPE(aplnelm, MyAplNelm2) = AS_BASETYPE(aplnelm, MyAplNelm1);
It is still allowed to exchange values between different 'strong' types; as long as you specify the correct type (name of the field in the struct) for each individual value.
AS_BASETYPE(aplnelm, MyAplNelm2) = AS_BASETYPE(aplrank, MyAplRank);
Please note you always need AS_BASETYPE to access a variable of one of the 'strong' types. This will make the code more verbose (please feel free to choose a shorter name for the macro), but there's nothing wrong with that. It's just a notion of metadata you are adding; it should actually improve maintainability.
I have a question related to struct initialization in C.
I have a struct:
struct TestStruct
{
u8 status;
u8 flag1;
u8 flag2;
};
I want a generic function/macro to initialize this struct and set the value of one parameter, eg status =1, easy way is:
TestStruct t = {};
t.status = 1;
However, by doing this I have set the value of status twice, first to 0 in init function and second set it to 1 (optimization does not help?).
(Please dont tell me t = {1,0,0} Im looking for a generic way)
I am thinking about a macro in init function, something like:
#define INIT_TESTSTRUCT (param, value) \
{ .status=0, .flag1=0, .flag2=0, .param=value }
TestStruct t = INIT_TESTSTRUCT(status, 0);
However, the compiler gives error "initialized field overwritten", because I have set the value of status twice.
Please help to point out how to alter the macro to achieve what I want, many thanks.
#define INIT_TESTSTRUCT(param, value) \
{ .param=(value) }
TestStruct t = INIT_TESTSTRUCT(status, 0);
should do it. The variable is then added in .data segment - as it is an initialized one - and all fields which are not mentionned explicitly are set to 0 by the compiler (instead of the linker or the loader).
You have a space in the wrong place:
#define INIT_TESTSTRUCT(param, value) \
{ .status=0, .flag1=0, .flag2=0, .param=(value) }
should do it.
The ( of the macro definition must come immediately after the macro name. Otherwise the parser takes this as a macro with no arguments and expands it to (param, value) ...etc... and in your case this then obviously is a syntax error.
Also note that it is usually a good idea to put () around parameters in the replacment text, to avoid syntax confusion.
Well, firstly
TestStruct t = {};
is illegal in C. If it compiled in your case, it must be a non-standard compiler extension. You can achieve the same effect by
TestStruct t = { 0 };
which is legal in C. It sets all fields in the entire struct to zeros.
Secondly, even with designated initializers C language follows the traditional "all-or-nothing" approach to initialization: if you initialize just one field of the aggregate, all other fields are implicitly initialized to zero.
Which means that in your case all you have to do is
TestStruct t = { .status = 1 };
to initialize the entire struct. status field will be set to 1, while all other fields will be set to zero.
So, your macro can be implemented as
#define INIT_TESTSTRUCT(param, value) { .param = value }
TestStruct t = INIT_TESTSTRUCT(status, 1);
There's no need to explicitly set all other fields to zero - it will happen by itself.