What is tagged structure initialization syntax? - c

struct file_operations scull_fops = {
.owner = THIS_MODULE,
.llseek = scull_llseek,
.read = scull_read,
.write = scull_write,
.ioctl = scull_ioctl,
.open = scull_open,
.release = scull_release,
};
This declaration uses the standard C
tagged structure initialization
syntax.
Can someone elaborate?

When you use aggregate initializers (initializers in {}) in the "traditional" ANSI C language (C89/90), you have to supply an individual initializer for each structure member in order, beginning with the first. For example
struct S { int a, b, c, d; };
struct S s = { 1, 2, 3, 4 };
/* 1 for `s.a`, 2 for `s.b` and so on... */
You are not required to specify initializers for all members, i.e. you can stop at any time (remaining members will be zero-initialized).
If for some reason you only cared to explicitly initialize the third member of the structure, you had to supply "dummy" explicit initializers for the first and the second members (just to get to the desired third)
/* We only care to explicitly initialize `s.c` */
struct S s = { 0, 0, 3 };
/* but we have to explicitly initialize `s.a` and `s.b` as well */
or abandon specific initialization entirely (likely replacing it with generic = { 0 }) and use a subsequent assignment to specific members
struct S s = { 0 };
s.c = 3;
One notable benefit of this assignment-based approach is that it is independent from the position of member c in the declaration of struct S.
The new specification of C language (C99) allows you to use "tagged" initializers by supplying the desired member name within the {}
struct S s = { .c = 3 };
That way you only explicitly initialize the desired member(s) (and have the compiler to zero-initialize the rest). This not only saves you some typing but also makes the aggregate initializers independent from the order in which the members are specified in the struct type declaration.
Aggregate initializers, as you probably know, can be used with arrays, too. And C99 supports "tagged" initialization with arrays as well. How the "tags" look in case of an array is illustrated by the following example
int a[10] = { [5] = 3 };
/* `a[5]` is initialized with 3, the rest of `a` is zero-initialized */
It is worth noting one more time that C language continues to stick to the "all or nothing" approach to aggregate initialization: if you specify an explicit initializer for just one (or some) members of a struct or an array, the whole aggregate gets initialized, and the members without explicit initializers get zero-initialized.

You're using the names of the members of the structure to initialise the structure. i.e. each member initialisation is "tagged" with that member's name.

Another benefit worth mention regarding this type of initialization is that it allows the reordering of structure members, which in some cases, can make performance improvements by, for instance ,placing pointers to frequently accessed members in the same hardware cache line.

Related

Struct definition Function of type Static

I came across the below line in one of the code:
static DATA_BLOCK_SOX_s data_blockSox = {.header.uniqueId = DATA_BLOCK_ID_SOX};
I want to know what form of Syntax is this and what is exactly happening here
Thanks
That's a C struct initializer with named fields (designated initializers).
static DATA_BLOCK_SOX_s data_blockSox = {.header.uniqueId = DATA_BLOCK_ID_SOX};
Creates a DATA_BLOCK_SOX_s in load-time allocated storage called data_blockSox scoped to this file, initializing all fields to binary zero except for header.uniqueId (where header is clearly a nested struct or union) which is initialized to DATA_BLOCK_ID_SOX.
I have used indentation to infer file scope. That could be incorrect. If it's inside a function it should be indented, but as we know, the compiler doesn't care.
In the unlikely case that you actually care about systems for which NULL is not binary zero, it has been pointed out that pointer fields should be initialized to NULL even on systems that have NULL as not binary zero. I have only ever seen that spec not followed.
This looks like C99. And should be something like:
struct Point {int x, y;}; // This would be the stand-in for DATA_BLOCK_SOX_s
typedef struct Point Point;
static Point point = { .y = 10, .x = 5 }; // here the members y and x get their values
In your case there is a nested struct called header. This as a member calles uniqueId.

Can someone please explain the difference between these two initiliazers?

I was wondering if someone could provide a detailed, simple explanation of the differences between the two of the following pieces of code. Given the following definition:
typedef struct {
stuff;
stuff_2;
} variable_t;
What is the difference between:
variable_t my_variable;
variable_t my_variable = {};
And if I do the first one, and then never fully initialize it, why does the compiler not throw an error?
Note: I am compiling with gcc -std=gnu99, so the second is valid and wound up being the solution to a problem that I had. I was wondering as to why.
It depends a little bit on where you place the respective variable definition, and it also seems depends on the compiler in use.
Automatic storage duration
Let's discuss the difference when the variables have automatic storage duration (which is the case if you place it in function or block scope and there without static keyword):
void someFunction() {
variable_t my_variable; // (1)
variable_t my_variable = {}; // (2)
}
(1) denotes a variable definition without an explicit initialization. And according this online C standard draft, it's value is indeterminate:
If an object that has automatic storage duration is not initialized
explicitly, its value is indeterminate.
(2) is a variable definition with explicit initialization through an initializer list without designators, i.e. without associating values to members through their names but only through the order of values (cf. 6.7.9 p17..21).
The interesting paragraph is 6.7.9 p21, which states that if the initializer list has fewer entries than the number of struct members, the members are initialized according to the initialization rule of static storage duration (i.e. to 0 or NULL as explained later):
If there are fewer initializers in a brace-enclosed list than there
are elements or members of an aggregate, ... , the remainder of the
aggregate shall be initialized implicitly the same as objects that
have static storage duration.
So it seems that if you write variable_t my_variable = {}, then all members are initialized to 0 or NULL.
However, as mentioned by aschepler in the comments, C initialization list grammar states that initializer lists must not be empty (cf. also cppreference.com):
... the initializer must be a non-empty, brace-enclosed,
comma-separated list of initializers for the members
So according to the standard an initializer list in C needs at least one entry; When testing it in my XCode8.3 environment with -std=gnu99, an empty initialization list seems to be supported, but I am aware that this is not a valid reference. So to be safe and not to depend on particular compiler extensions, you should actually write:
variable_t my_variable = {0};
Static storage duration
At file scope, your variable definitions will have static storage duration, and then other rules apply (cf. 6.7.9 (10)):
(10) ... If an object that has static or thread storage duration is
not initialized explicitly, then:
if it has pointer type, it is initialized to a null pointer;
if it has arithmetic type, it is initialized to (positive or unsigned) zero;
if it is an aggregate, every member is initialized (recursively) according to these rules, and any padding is initialized to zero bits;
if it is a union, the first named member is initialized (recursively) according to these rules, and any padding is initialized
to zero bits;
...
(21) If there are fewer initializers in a brace-enclosed list than there are elements or members of an aggregate, ... the remainder of the aggregate shall be initialized implicitly the same as objects that have static storage duration.
So if you write...
#include <stdio.h>
variable_t my_variable; // (1)
variable_t my_variable = {}; // (2)
then (1) and (2) actually yield the same result because for the not explicitly initialized variable (1), paragraph (10) applies, and for the explicitly but empty initialized variable (2), according to paragraph (21), every member falls back to the initialization rule of (10).
Again, compilers may not support empty initalization lists as discussed above.
Hope it helps (because it has been a lot of typing :-) )
When you declare:
variable_t my_variable; // a variable_t that is uninitialized
variable_t my_variable = {}; // a variable_t initialized with zeroes.
Note that for variables declared at file-scope, this doesn't really matter since the data is - normally- zeroed out before program start.
Used on the stack, the second line efficiently fills my_variables with zeroes. Same as if there was a call to:
memset(&variable, 0, sizeof(variable));
This works because, in C, you can copy a structusing =.
Here's a little game the computer is sure to win.
struct A { /*...*/ };
void main()
{
A a; // random
A b = {};
if (memcmp(&a, &b, sizeof(A)) == 0)
{
printf("You win\n");
return;
}
a = b;
if (memcmp(&a, &b, sizeof(A)) == 0)
{
printf("I win\n");
}
}

Usb device id table understanding

I am trying to understand different ways linux kernel initialize structures. In this query I wrote a sample usb driver but I do not understand some points, pointed as comments preceding ??
static struct usb_device_id pen_table[] = //?? why pen_table is an array
{
{ USB_DEVICE(0xaaaa , 0x8816) }, //??what type of array initialization is this
{} /* Terminating entry */ //??how this terminates
};
I tried to initialize device id table in this way, but I am getting errors as near initialization
static struct usb_device_id pen_table = {
.match_flags = USB_DEVICE_ID_MATCH_DEVICE,
.idVendor=0xaaaa,
.idProduct = 0x8816,
};
You should have Linux kernel source at hand to really understand this.
Why pen_table is an array?
It wil be necessary in MODULE_DEVICE_TABLE (see Hard time in understanding MODULE_DEVICE_TABLE(usb, id_table) usage) and in defining instance of usb_driver struct, see http://opensourceforu.efytimes.com/2011/11/usb-drivers-in-linux-2/.
what type of array initialization is this?
USB_DEVICE is a macro defined in include/linux/usb.h:
#define USB_DEVICE(vend, prod) \
.match_flags = USB_DEVICE_ID_MATCH_DEVICE, \
.idVendor = (vend), \
.idProduct = (prod)
how this terminates?
C standard says:
The initialization shall occur in initializer list order, each
initializer provided for a particular subobject overriding any
previously listed initializer for the same subobject; all subobjects
that are not initialized explicitly shall be initialized implicitly
the same as objects that have static storage duration.
and:
If an object that has automatic storage duration is not initialized
explicitly, its value is indeterminate. If an object that has static
storage duration is not initialized explicitly, then:
if it has pointer type, it is initialized to a null pointer;
if it has arithmetic type, it is initialized to (positive or
unsigned) zero;
if it is an aggregate, every member is initialized (recursively)
according to these rules;
if it is a union, the first named member is initialized
(recursively) according to these rules.
Thanks to this, id_table is defined as a pointer and not as an array inside usb_driver:
const struct usb_device_id *id_table;
Instead of passing an array size independently a function that uses id_table will increment pointer to id_table until one of its elements is NULL. See this short example that represents this technique:
#include <stdio.h>
#include <stdlib.h>
struct small
{
int a;
int b;
};
struct big
{
struct small *s;
};
struct small table[] =
{
{1, 1},
{2, 2},
{3, 3},
{}
};
int main(void)
{
struct big b = {
.s = table
};
const struct small *s;
/* traverse through table using pointer arithmetic */
for (s = b.s; s->a; s++)
{
printf("%d\n", s->a);
printf("%d\n", s->b);
}
exit(0);
}
I tried to initialize device id table in this way, but I am getting
errors as near initialization
I don't, are you sure you're not trying to redefine pen_table? What's an error message?
It's an array because it's how the data structure is defined and used.
You have n number of entries, and then a terminating entry (in this case, all zeros).
Wherever this array is used in initialization, it will start at the table symbol and consume entries until it hits the terminator, then stop. This way you don't need to communicate the number of entries as well.
This pattern facilitates late binding of configuration data with the library, and allows more compile time configuration, rather than run time configuration, and also requires fewer things to be in sync to operate correctly (so less chance for error).
Your second struct doesn't have a terminator, so the thing that's parsing the table just keeps on going and going and going until it crashes or gets errors.

Unfamiliar syntax for initializing an array/struct, looking for explanation

I'm looking through the "Processor Modeling Guide" provided by a company named OVP (a product similar to qemu). In it, there's a little code snippet resembling the following:
static or1kDispatchTableC dispatchTable = {
// handle arithmetic instructions
[OR1K_IT_ADDI] = disDefault,
[OR1K_IT_ADDIC] = disDefault,
[OR1K_IT_ANDI] = disDefault,
[OR1K_IT_ORI] = disDefault,
[OR1K_IT_XORI] = disDefault,
[OR1K_IT_MULI] = disDefault
};
I've never seen syntax like this before. irrelevant stuff about C++ removed
At the moment I don't have the ability to download/look at their stuff to look at how anything is defined, hence my question. If you recognize this syntax, can you weigh in?
edit
or1kDispatchTableC is a typedef for a pointer of type or1kDispatchTableCP, but I still don't have anything on what or1kDispatchTableCP is.
Well, assuming your first line is a typo, or or1kDispatchTableC is an array type, so that this is actually an array declaration, this looks like a C11 explicitly initialized array. The line
[OR1K_IT_ADDI] = disDefault,
initializes element OR1K_IT_ADDI to disDefault. Both of those need to be constant expressions -- OR1K_IT_ADDI is probably a #define or an enum tag.
I'm pretty sure that C++11 does NOT support this syntax, though some compilers (that also support C11) might support it as an extension.
From the names, I would guess that this is actually an array of function pointers.
This is called designated initializers and is a C feature (supported since C99). It allows addressing array and structure/union elements directly, filling the gaps with default values.
struct foo { int a[10]; };
struct foo f[] = { [5].a[3] = 20 };
Now this results in 5 elements of struct foo, all initialized to zero followed by a sixth element of struct foo with the 4th element of a initialized to 20.
Like someone else suspected, this is not supported by C++.

Array initialisation warning

I'm trying to initialise a structure which ends with an array[0] (here, char iedata[0]) for the actual packet payload. If I try to initialise it inline, like this:
struct some_packet pkt = {
.elem1 = blah, .elem2 = bleh,
.iedata = {
1, 2, 3, 4
}
};
I get a warning from gcc:
warning: (near initialization for ‘pkt.iedata’)
Is there any good way to mark that this is a proper initialisation?
If you're able to compile in C99 mode, you could try using standard flexible length arrays rather than the zero-length hack: http://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
Note that in GCC 3.0 and newer, extra entries in an array initialiser will be discarded (per the documentation linked above).
As you are using C99 initialization, why not make the member a proper FAM, i.e. char data[];
The only way to create valid struct's with a FAM (or struct hack member) is by dynamically allocating the correct amount of excess storage for the last member so, as the warning suggests, your local initialization isn't valid.

Resources