How to indent in vim for designated initializers? - c

How to do proper indentation in vim for designated initializers of structs (in C)?
This is how it is indented by default:
typedef struct {
int foo;
int bar;
} child_t;
typedef struct {
child_t child;
} parent_t;
int main(int argc, char *argv[]) {
parent_t p;
p.child = (child_t) {
.foo = 1,
.bar = 2,
};
}
How can I have it indented like this?
typedef struct {
int foo;
int bar;
} child_t;
typedef struct {
child_t child;
} parent_t;
int main(int argc, char *argv[]) {
parent_t p;
p.child = (child_t) {
.foo = 1,
.bar = 2,
};
}
I've tried quite a few options from https://vimdoc.sourceforge.net/htmldoc/indent.html but haven't been able to make it work.
Removing (child_t) allows it to do indent properly, but in that case the gcc compiler complains with an expected expression before ‘{’ token error message (because apparently it isn't able to infer what type p.child is.

If you use vim and want propper formatting, I can recomd to use coc vim and ccls. Further you can use clang-format to format your source files propperly.

Related

Struct array typedef in struct shows incomplete data

I'm having trouble with a piece of code where a typedef array is created of a struct. That typedef is then used in another struct.
When receiving the typedef in a function and initialising the struct with the typedef in it, I only get data of the first element in the array.
Below I have a simplified example of what I'm getting at the moment.
struct simple_struct {
double a;
};
typedef struct simple_struct arr_typedef[2];
struct struct_with_typedef {
const arr_typedef typedef_arr;
};
void foo(const arr_typedef arg_s) {
struct struct_with_typedef test = {
*arg_s
};
int i;
for (i = 0; i < 2; i++) {
printf("value: %f \n", test.typedef_arr[i].a);
}
}
int main(int argc, char* argv[]) {
arr_typedef d_test = { {1}, {2} };
foo(d_test);
return 1;
}
When compiled, using gcc 4.4, and run I see the following output:
~/public > ./test
value: 1.000000
value: 0.000000
Would someone be able to explain why the value of the second item isn't available?
If I leave out the dereference I get the following error whilst compiling, which I also don't get:
test.c:82: error: incompatible types when initializing type 'double' using type 'const struct simple_struct *'
I have removed the typedef and the same result persists. Sort of understand that indeed that one initialiser value is given. But there is only one member in the struct, or are they expanded in the background?
If so, how would you initialise both values?
struct simple_struct {
double a;
};
struct struct_with_arr {
const struct simple_struct struct_arr[2];
};
void foo(const struct simple_struct arg_s[2]) {
struct struct_with_arr test = {{*arg_s}};
int i;
for (i = 0; i < 2; i++) {
printf("value: %f \n", test.struct_arr[i].a);
}
}
int main(int argc, char* argv[]) {
struct simple_struct d_test[2] = { {1}, {2} };
foo(d_test);
return 1;
}
In this declaration
struct struct_with_typedef test = {
*arg_s
};
there is used an object of the type struct simple_struct to initialize an array of the type const arr_typedef.
Firstly you need to enclose the initializer in braces and add an initializer for the second element of the array if you want to do so.
A correct way to initialize the array is the following
#include <stdio.h>
struct simple_struct
{
double a;
};
typedef struct simple_struct arr_typedef[2];
struct struct_with_typedef
{
const arr_typedef typedef_arr;
};
void foo( const arr_typedef arg_s )
{
struct struct_with_typedef test =
{
{ arg_s[0], arg_s[1] }
};
for ( int i = 0; i < 2; i++ )
{
printf("value: %f \n", test.typedef_arr[i].a);
}
}
int main( void )
{
arr_typedef d_test = { {1}, {2} };
foo(d_test);
return 0;
}
The program output is
value: 1.000000
value: 2.000000
You can write the initializers also the following way
struct struct_with_typedef test =
{
{ *arg_s, *( arg_s + 1 ) }
};
Take into account that an array designator used as an initializer expression is implicitly converted to pointer to its first element. Dereferencing the pointer you get the first element itself.
There is no syntax in C for initializing an array with a single initializer representing another array to copy values from.
To fix your code you could do one of these options:
List the members: struct struct_with_arr test = {{arg_s[0], arg_s[1]}};
Change the function to accept struct struct_with_arr as the parameter type, in which case you can use struct struct_with_arr test = arg;
Copy without an initializer: struct struct_with_arr test; memcpy(&test.struct_arr, arg_s, sizeof test.struct_arr);. (Actually you can't use this option since you have defined the struct element as const ... not really a great idea in the first place in my opinion)
For completeness I will mention the code:
struct struct_with_arr foo = *(struct struct_with_arr *)arg_s;
This is one of those things that is technically undefined behaviour (if the argument source was not actually a struct_with_arr) but is likely to work on any actual compiler that exists. My advice would be to not do this.

What is best solution for initialize struct array?

First solution:
struct str {
char *name;
int flag;
};
enum {
HELP,
OUTPUT,
OTHER
};
typedef struct str table;
table arr[] = {
{ "help", HELP },
{ "output", OUTPUT },
{ NULL, OTHER },
};
int main(int argc, char **argv) {
table *opt = arr;
printf("%s\n", (opt+HELP)->name);
printf("%s\n", (opt+OUTPUT)->name);
return 0;
}
Second solution:
struct str {
char *name;
int flag;
};
enum {
HELP,
OUTPUT,
OTHER
};
typedef struct str table;
table arr[OTHER];
void start_table() {
arr[HELP] = (struct str) { "help", HELP };
arr[OUTPUT] = (struct str) { "output", OUTPUT };
arr[OTHER] = (struct str) { NULL, OTHER };
}
int main(int argc, char **argv) {
start_table();
table *opt = arr;
printf("%s\n", (opt+HELP)->name);
printf("%s\n", (opt+OUTPUT)->name);
return 0;
}
What are the best? Second solution change automatically if I add or change any element of the array, but is efficient? Is the best enumerate or using the #define preprocessor directive?
It depends!
When initialization can be used, use it — so the first solution is often better, especially if the code never changes the structure (array) contents.
If your code can change the contents but might need to be able to reset to the original state, then the initialization function becomes more appropriate and using direct initialization is not appropriate.
There is no one 'best' solution; what is best depends on what you need to do with the array.
Using a C99 specific intializer syntax, you can get the advantages of the second approach in a static initializer:
#include <stdio.h>
struct str {
const char *name;
int flag;
};
enum {
HELP,
OUTPUT,
OTHER,
};
typedef struct str table;
table arr[] = {
[HELP] = { "help", HELP },
[OUTPUT] = { "output", OUTPUT },
[OTHER] = { NULL, OTHER },
};
int main(int argc, char **argv) {
table *opt = arr;
printf("%s\n", opt[HELP].name);
printf("%s\n", opt[OUTPUT].name);
return 0;
}
The advantage of this technique is it makes no assumption on the order of the enum values, nor on their actual values as long as they are positive, distinct and reasonably small.

Macro that knows void * allocation type

Let have this code as example:
typedef struct {
int value;
char another;
} foo;
typedef struct {
float yet_another;
long really_another;
} bar;
typedef struct {
char* name;
void* data;
} gen;
int main(int argc, char** argv) {
gen foo_gen, bar_gen;
foo_gen.name = "Foo";
foo_gen.data = (foo*) malloc(sizeof(foo));
bar_gen.name = "Bar";
bar_gen.data = (bar*) malloc(sizeof(bar));
((foo*) foo_gen->data)->value = 0;
((bar*) bar_gen->data)->yet_another = 1.0f;
return 0;
}
This code would work ok, so I defined 2 macro to facilitate my work:
#define FOO_DATA(N, D) ((foo*) N->data)->D
#define BAR_DATA(N, D) ((bar*) N->data)->D
But it seems to be too repetitive. I want it to make more generic, making the macro to know which type it should cast. I tried using __auto_type:
#define DATA(N, D) (__auto_type N->data)->D
But it didn't work. It seems too that typeof don't works with macros. How should I do it?
If me and the other commenters understand correctly, you want to be able to do something like this:
struct a {
int field1;
} a;
struct b {
int field2;
} b;
void *self1 = &a;
void *self2 = &b;
int f1 = MAGIC(self1)->field1;
int f2 = MAGIC(self2)->field2;
for some definition of MAGIC.
This is not possible in C.
Expanding on my comment: you would have to group your common fields into another struct and make that the first field of the possible structs in self->data:
struct common {
int foo;
};
struct a {
struct common common;
int bar;
};
struct b {
struct common common;
int baz;
};
#define $(D) (((struct common*) self->data)->D)

Visual Studio C2085 on Array Definition

In a .h file I have an extern declare:
extern const some_struct SomeArray[];
In the .c file I have the definition:
const some_struct SomeArray[] =
{
1, 2, 3, 4, 5 etc.
};
VS Express 2013 is complaining with a C2085, 'not in formal parameter list', which according to MSDN, means a function prototype wasn't declared before the definition, but this isn't a function, so I'm a bit lost...
Edit: More detail...
An entire .h:
#ifndef MYHEADER_H_
#define MYHEADER_H_
#include <stdint.h>
typedef uint32_t my_event;
typedef uint32_t my_state;
typedef my_event(*my_handler)(my_event, void *);
typedef struct my_table
{
my_event Event;
my_handler Handler;
my_state NextState;
} my_table;
#endif
and it's .c(pp):
#include "myheader.h"
#include "stdafx.h"
int _tmain(int argc, _TCHAR* argv[])
{
typedef enum TestEnum
{
A,
B,
C,
} TestEnum;
my_event functionA(my_event E, void *pointer);
my_event functionB(my_event E, void *pointer);
const my_table TestArray[] =
{
A, functionA, A,
};
return 0;
}
this is an example of how to initialize an array of structs:
typedef struct { int a; char b; } A;
const A arr[] = {
{ 3, 'a' },
{ 7, 't' }
};
if that does not help you, show us a complete compilable
minimal example that exhibits the error

How to hold a const value in a struct in C (not C++)?

How can I hold a constant value in a struct? If I put const at LEBEL0 I would not be able to assign to it at LEBEL1. But if I do not put const at LEBEL0, then I will get qualifier lost warning at LEBEL1. Is there any way to do this? I came up with a dirty solution (below) but I think there could be a better one...
typedef struct _MyStruct
{
const SomePointerType pktData; <--LABEL0
}MyStruct;
const SomePointerType SomeFunctionICannotModify()
{
…
}
void SomeFunction()
{
MyStruct data;
….
data.pktData = SomeFunctionICannotModify(); <--LABEL1
....
SomeSubFunction(&data);
}
void SomeSubFunction(MyStruct* data)
{
this function does not modify any fields in "data".
}
PS: The code above is a "model", not a real code, to illustrate my problem. It does not have all the codes in my actual program. Please do not ask questions like "why would you do that", "you do not have to do that", "that code does not compile" and so on.
My dirty solution
typedef struct _ConstHolder
{
const SomePointerType pktData;
}ConstHolder;
typedef struct _MyStruct
{
ConstHolder holder;
}MyStruct;
void SomeFunction()
{
MyStruct data;
….
ConstHolder holder = {SomeFunctionICannotModify()};
data.holder = holder;
....
SomeSubFunction(&data);
}
Your question is difficult to understand, but you may be under the misapprehension that you cannot modify pktData after you've assigned to it. This is not true. Consider the following, which is perfectly legal:
const char * str = "hello";
printf("%s\n", str);
str = "goodbye";
printf("%s\n", str);
The const does not say that you cannot reassign the pointer, but instead that you cannot alter the data to which it points.
It looks to me like the problem is that you are using typedef along with const. The thing about C is that const is not as well implemented and usable as it is in C++. And typedef is not well done either.
This article talks a bit about const in C. As does this article as well on const in C.
For instance if you use the following, it will compile with no problems in Visual Studio 2005
typedef char * pchar;
typedef struct {
int i;
int j;
} Thing;
typedef Thing * SomePtr;
typedef struct {
// const SomePtr pSome;
// const pchar mychar;
const char * mychar;
const Thing *pSome;
} MyStruct;
const SomePtr SomePtrFunc ()
{
static Thing jj = {1, 2};
return &jj;
}
int main(int argc, char **argv)
{
MyStruct josey;
josey.pSome = SomePtrFunc();
josey.mychar = "this";
return 0;
}
If I were to then try to modify what is pointed to by josey.pSome by doing something like adding a line of code such as josey.pSome->i = 0; then I will see a compilation error of error C2166: l-value specifies const object.
However if you use the following code with comments switched around, you get an error message of error C2166: l-value specifies const object
typedef char * pchar;
typedef struct {
int i;
int j;
} Thing;
typedef Thing * SomePtr;
typedef struct {
const SomePtr pSome;
const pchar mychar;
// const char * mychar;
// const Thing *pSome;
} MyStruct;
const SomePtr SomePtrFunc ()
{
static Thing jj = {1, 2};
return &jj;
}
int main(int argc, char **argv)
{
MyStruct josey;
josey.pSome = SomePtrFunc(); // <- error C2166: l-value specifies const object
josey.mychar = "this"; // <- error C2166: l-value specifies const object
return 0;
}
Finally what you could do is to make the typedef to include the const qualifier which would then make the const qualifier part of the type:
typedef const char * pchar;
typedef struct {
int i;
int j;
} Thing;
typedef const Thing * SomePtr;
typedef struct {
SomePtr pSome;
pchar mychar;
// const char * mychar;
// const Thing *pSome;
} MyStruct;

Resources