Clang-format: how to format C struct initializer this way - c

I'm using the linux kernel .clang-format as a reference, but this part is bothering me.
How can I get clang-format to format this code
const struct my_struct hello = {.id = 0,
.modsmin = 10,
.modsmax = 20,
.strengthmin = 0,
.strengthmax = 100,
.color = COLOR_FOREGROUND };
to this
const struct my_struct hello = {
.id = 0,
.modsmin = 10,
.modsmax = 20,
.strengthmin = 0,
.strengthmax = 100,
.color = COLOR_FOREGROUND
};

Looking at the documentation, there don't seem to be any clang-format style options which will do what you want.
But, you can use the "comma-after-last-item" trick. Put a comma after the last designated initializer, before the final closing brace. I believe this is still valid C code. Then clang-format will put each initializer on a separate line, and this will move the indentation back to what you're looking for. So the output would look like this:
const struct my_struct hello = {
.id = 0,
.modsmin = 10,
.modsmax = 20,
.strengthmin = 0,
.strengthmax = 100,
.color = COLOR_FOREGROUND,
};
This behavior is not documented anywhere (as far as I know), so I suppose it could be changed in the future. But this behavior has been there for many years and many versions of clang-format so I think it is reasonable to rely on it.

Related

C Nested Structs Initialization

I'm an avid embedded c programmer. I recently started working with the ESP IDF framework to program the ESP32. Even though I think that the following code is initializing a struct within a struct (not sure); but for some reason, I cannot grasp how and why there is just a ".mode" rather than the struct's name within gpio_config_t + ".mode". This is just an example but there are several instances of similar types of initialization.
for example:
typedef struct example_struct{
int mode;
int pull_up_en;
.
.
}example_struct;
typedef struct gpio_config_t
{
example_struct test;
} gpio_config_t;
Shouldn't the initialization be done the following way?
gpio_config_t io_test_config =
{
test.mode = 3;
test.pull_up_en = 1;
etc
};
Can someone please clarify this?
The actual type of initialization I'm referring to:
gpio_config_t io_conf = {
.mode = GPIO_MODE_OUTPUT,
.pull_up_en = 1,
};
The technical term for the notation you're using is designated initializers. The designators always start with either a . or a [, and there are no semicolons in the initializers (until after the } at the end of the initializer). There are many ways that you could initialize that structure, including:
gpio_config_t io_test_config1 =
{
.test.mode = 3, .test.pull_up_en = 1
};
gpio_config_t io_test_config2 =
{
.test = { .mode = 3, .pull_up_en = 1 }
};
gpio_config_t io_test_config3 =
{
{ 3, 1 }
};
gpio_config_t io_test_config4 =
{
3, 1
};
The last one doesn't compile cleanly with GCC when you specify -Wmissing-braces (usually activated by -Wall).

Is there a quick way to initialise a struct array with the same attributes?

struct child {
char name[32];
int height;
};
struct child group_a[8];
I'd like to initialise every child in group_a with the same name and height, for example name = "XXX" and height = "100".
Is there a quick of doing it, rather than struct child group_a[8] = {{"XXX", 100}, {"XXX", 100}, ..., {"XXX", 100}}?
It cannot be done in standard C without deeper preprocessor magic. However there is an extension for ranges in designated initializers. It is supported by main compilers (GCC, CLANG, Intel).
struct child group_a[] = {
[0 ... 7] = { .name = "XXX", .height = 100 }
};
Try using compound literals like this:
int i = 8;
while(i--)
group_a[i] = (struct child) { "XXX", 100 };
Maybe a bit lame, but why not use a macro?
#define H {"XXX", 100}
struct child group_a[8] = {H, H, H};

Nim import typedef from C header file

I'm wondering if I can import a C type definition or if I need to redefine it in Nim?
Looking at program called jhead interfacing with this proc
int ReadJpegFile(const char * FileName, ReadMode_t ReadMode);
The second parameter ReadMode_t is an enum type in jhead.h
typedef enum {
READ_METADATA = 1,
READ_IMAGE = 2,
READ_ALL = 3,
READ_ANY = 5 // Don't abort on non-jpeg files.
}ReadMode_t;
Can I import this ReadMode_t? Or do I have to redfine it like below
type
ReadMode_t* = enum
READ_METADATA = 1, READ_IMAGE = 2, READ_ALL = 3, READ_ANY = 5
The Nim compiler needs to know about those C constants, so you have to define them to use them from Nim. However, this tedious copying can be simplified and even automated to some degree with tools like c2nim. In fact, if you take the following test.h file:
typedef enum {
READ_METADATA = 1,
READ_IMAGE = 2,
READ_ALL = 3,
READ_ANY = 5 // Don't abort on non-jpeg files.
}ReadMode_t;
int ReadJpegFile(const char * FileName, ReadMode_t ReadMode);
and run c2nim test.h, it will generate the following test.nim file for you, saving most of the tedious translation:
type
ReadMode_t* = enum
READ_METADATA = 1, READ_IMAGE = 2, READ_ALL = 3, READ_ANY = 5
proc ReadJpegFile*(FileName: cstring; ReadMode: ReadMode_t): cint

Working with C Structures

I'm developing some code for a small gaming device I've designed. I've got completely stuck trying to build what is ultimately a Graph of map locations.
I have 2 structs:
typedef struct point {
int x;
int y;
} point;
typedef struct location {
const point portal_in;
const point portal_out;
const byte *map;
const byte width;
const byte height;
struct location *portals[8];
point player;
struct location *return_to;
} location;
Each location has a list of other locations that it links to, as well as the location it links from.
I tried to set up the locations like this:
location build_locations()
{
location village = {
.portal_in={15, 14},
.portal_out={0, 0},
.map=&VILLAGE[0],
.width=32,
.height=16,
.player={15, 14},
.return_to=0
};
location loc = {
.portal_in={8, 7},
.portal_out={11, 10},
.map=&HOUSE[0],
.width=8,
.height=8,
.player={0, 0},
.return_to=&village
};
village.portals[0] = &loc;
return village;
}
this gets called in my main() function:
location current_location = build_locations();
And this works, up to a point - I can draw the village map and move the player around it:
display_map(&current_location);
display_player(&current_location);
and so on. The trouble comes when I want to swap into a new location.
If I try and reassign current_location, I get a compiler error complaining about assignment to read only variable:
current_location = current_location.portals[0];
This is easily the most complex code I've written in C, so I know I'm out of my depth when it comes to structures and pointers, but I'm trying to learn and I've come a long way already.
Is there a better way to do what I'm trying to do? Or is there something obvious I have missed?
Thanks
EDIT:
This is the most minimal example I can come up with:
typedef unsigned char byte;
static const byte VILLAGE[] = {
0, 0, 0, 0, 175, 181, 181, 181, 181, 181, 181, 175, 0, 0, 0, 0,
/// And so on - indices of tiles defined elsewhere but irrelevant here
};
static const byte HOUSE[] = {
0, 0, 0, 0, 175, 181, 181, 181, 181, 181, 181, 175, 0, 0, 0, 0,
/// And so on - indices of tiles defined elsewhere but irrelevant here
};
typedef struct point {
int x;
int y;
} point;
typedef struct location {
const point portal_in;
const point portal_out;
const byte *map;
const byte width;
const byte height;
struct location *portals[8];
point player;
struct location *return_to;
} location;
location build_locations()
{
location village = {
.portal_in={15, 14},
.portal_out={0, 0},
.map=&VILLAGE[0],
.width=32,
.height=16,
.player={15, 14},
.return_to=0
};
location loc = {
.portal_in={8, 7},
.portal_out={11, 10},
.map=&HOUSE[0],
.width=8,
.height=8,
.player={0, 0},
.return_to=&village
};
village.portals[0] = &loc;
return village;
}
int main(void)
{
location current_location = build_locations();
if (current_location.player.x == 5 && current_location.player.y == 4)
{
current_location = current_location.portals[0];
}
}
Runtime problem:
Problem is simple. Both village and loc are on stack.
on return, you get a copy of village, but no copy for loc. so loc will be released after return. You can use a code like this to solve your problem:
village.portals[0] = calloc(1, sizeof(*(village.portals[0])));
memcpy(&village.portals[0], &loc, sizeof(loc)); //->or just assign village.portals[0] directly
Update:
Compile problem
Yea comments on current_location is correct too. You can solve it like this:
current_location = *(current_location.portals[0]);
or use pointers completely for accessing data.
But just remember runtime problem that I mentioned is very important and very hard to trace later too.
Update 2:
I just noticed that you have const members in your structure. that's why you get those read-only errors if you use assignment only. You can solve this problem by removing those consts from location structure or you can do it like this:
memcpy(&current_location, current_location.portals[0], sizeof(current_location));
but I don't suggest this approach, it is better to use pointers to prevent this problem.

How do I suppress PC-Lint errors for C99-style initialization of structure members?

I am using PC-Lint 8.00x with the following options:
+v -wlib(1) +fan +fas
I receive a number of error messages from PC-Lint when I run code similar to the following:
typedef union
{
struct
{
unsigned int a : 4;
unsigned int b : 4;
unsigned int c : 4;
unsigned int d : 4;
} bits;
unsigned short value;
} My_Value;
int main (void)
{
My_Value test[] =
{
{
.bits.a = 2,
.bits.b = 3, //Errors 133 and 10
.bits.c = 2,
.bits.d = 3,
},
{
.bits.a = 1,
.bits.b = 1, //Errors 133 and 10
.bits.c = 1,
.bits.d = 0,
},
};
/* Do something meaningful. */
return 0;
}
The reported errors are defined by PC-Lint as follows:
Error 133: Too many initializers for aggregate 'unknown-name'
Error 10: Expecting '}'
I have tried searching Gimpel and have done some Google searches, but I cannot find anything useful. The code functions as intended and everything initializes properly. Here are my questions.
1. Does PC-Lint 8.00x support C99 style initialization of structure members?
2. If so, what options/flags do I have to set for PC-Lint to suppress these messages globally?
EDIT
I should have been more detailed in regards to question 2. I would like to globally suppress these messages in regards to my usage of designated initializers as shown above. I cannot suppress them globally for all situations as these errors can detect true errors in the code.
As far as I can tell, this syntax:
My_Value test[] =
{
{
.bits.a = 2,
.bits.b = 3,
.bits.c = 2,
.bits.d = 3,
},
{
.bits.a = 1,
.bits.b = 1,
.bits.c = 1,
.bits.d = 0,
},
};
is valid in C99 (and C11). Looking in section 6.7.8 of the standard, the thing preceding the = in an initializer is a designator-list, which is a sequence of one or more designators. .bits.a is valid in that context.
Apparently PC-Lint doesn't support that syntax. (You might want to notify the maintainers, unless it's already supported in a later version.)
As a workaround, if you change it to this:
My_Value test[] =
{
{ .bits =
{
.a = 2,
.b = 3,
.c = 2,
.d = 3,
},
},
{ .bits =
{
.a = 1,
.b = 1,
.c = 1,
.d = 0,
},
},
};
it's still valid C (and arguably clearer) and, based on what you just wrote in a comment, PC-Lint accepts it.
(If you want to be even more explicit, you might consider adding [0] = and [1] = designators.)
UPDATE : QUoting a new commment:
The good people at Gimpel software have responded stating that "this
appears to be a bug" and are working to correct it.
Not sure to the C99 and 8.00x support question, as I have 9.00k installed. But 9.00k dislikes your form of union initialization, but Visual Studio has no issue.
But for Jacchim Pileborg's case it just emits a Info 708: union initialization while might be safer to turn off.
As noted in the comments you dont want to fully globally remove these error types, so -e133 and -e10 will not solve your problems.
So using Joachim's form, I can using a macro suppress it like so:
typedef union
{
struct
{
unsigned int a : 4;
unsigned int b : 4;
unsigned int c : 4;
unsigned int d : 4;
} bits;
unsigned short value;
} My_Value;
#define MY_UNION(A,B,C,D) /*lint -save -e708*/{{.a=(A),.b=(B),.c=(C),.d=(D)}}/*lint -restore*/
int main(void)
{
My_Value test[] =
{
MY_UNION(2, 3, 2, 1),
MY_UNION(1, 2, 3, 4)
};
return 0;
}
Ugly, but as you have nothing to make the lint commands to stick to as it's all anonymous, you ether have to put inline commands explicitly or via a macro.

Resources