This question already has answers here:
What does a dot before the variable name in struct mean?
(2 answers)
Closed 9 years ago.
I am looking at some code that has this kind of struct definition in it. At first, I thought it was a special way of defining a struct that defined it and instantiated one at the same time. However, my predictions about how this type of code behaves were wrong after I tested some similar code myself. Can someone tell me what this code does/where I could look online to see a description of this kind of code?
struct Error e = { .code = 22,
.msg = 22100 };
That's not a struct definition, it's a designated initializer. It's setting the code field to 22 and the msg field to 22100. Logically, you could rewrite it something like:
struct Error e = {0};
e.code = 22;
e.msg = 22100;
You can do something similar with arrays:
int a[5] = {
[3] = 12,
[4] = 17
};
It's a C99 designation initializer.
Designation initializers allow you to initialize aggregate members in any order and they also allow you to omit members. Members that are not designated explicitly are initialized to 0.
For example, a initialization here:
struct bla {int x; int y; int z;};
struct bla a = {.x =1, .z = 1};
is equivalent to C89 initialization below:
struct bla a = {1, 0, 1};
A note on terminology, it's a designation initializer and not a designated initializer. See defect report DR#253:
"The tem "designated initializer" is never mentioned in the Standard though it appears in the index and new features section (the Standard uses the term "designation initializer" in the text).
This is called a designated initializer, it's initializing an instance of the struct.
Here’s GCC’s manual page about how to use them.
Related
This question already has answers here:
What does a dot before the variable name in struct mean?
(2 answers)
Closed 1 year ago.
I came across some C code with an unusual structure initialization syntax.
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long)tx,
.rx_buf = (unsigned long)rx,
.len = ARRAY_SIZE(tx),
.delay_usecs = delay,
.speed_hz = speed,
.bits_per_word = bits,
};
First off, I have no idea what this is called. What is this known as? Perhaps "dot initialisation syntax" as I suggested in the question title? I have not encountered this before so I don't know how to describe it.
Secondly, this is valid C code as it compiles, however what dialect of C is this and when was it introduced? (Was it new in C11?)
Thirdly, if some members of the struct are omitted, are those members initialized to zero. If not, is there a way to initialize the struct such that omitted members are zero.
(For example spi_ios_transfer also contains a field cs-change which has been omitted here.)
Finally is this permitted also in C++, and does it work with C++ classes?
First off, I have no idea what this is called.
Designated initializer
Secondly, this is valid C code as it compiles, however what dialect of C is this and when was it introduced? (Was it new in C11?)
C99 and later
Thirdly, if some members of the struct are omitted, are those members initialized to zero.
Yes
Finally is this permitted also in C++, and does it work with C++ classes?
It was introduced in C++20
I came across the following code which declares char * array in C in a non-standard way:
/* Message Type description array */
char *msgType[M_LAST_MSG] =
{
[M_INIT_MSG] "Init",
[M_RESET_MSG] "Serdes Reset"
};
M_INIT_MSG, M_RESET_MSG and M_LAST_MSG are enumerations with corresponding values of 0, 1 and 2.
According to the formal C documentations, the variables inside this array are string (literals) so what is the purpose of using those enumerations in that manner and is there any documentation to back it up?
Compiled with ARM gcc compiler gcc-arm-none-eabi.
This syntax allows you to initialize specific elements of an array by index. You can use either int or enum values to specify which array element to initialize. This way, the values you assign don't need to be consecutive.
If for example you had this:
int x[5] = { [2] 3, [4] 7 };
It would be equivalent to this:
int x[5] = { 0, 0, 3, 0, 7 };
In the above example, the enum values specify that elements 0 and 1 of the array are initialized to "Init" and "Serdes Reset".
From section 6.7.8 of the C99 standard:
18 Each designator list begins its description with the
current object associated with the closest surrounding brace
pair. Each item in the designator list (in order) specifies
a particular member of its current object and changes the
current object for the next designator (if any) to be that member.
The current object that results at the end of the designator list is
the subobject to be initialized by the following initializer.
33 EXAMPLE 9 Arrays can be initialized to correspond to the
elements of an enumeration by using designators:
enum { member_one, member_two };
const char *nm[] = {
[member_two] = "member two",
[member_one] = "member one",
};
EDIT:
Note that the syntax from the standard includes a = while OP's example does not. The syntax without = is apparently an old syntax supported by GCC. Compiling OP's example gives the following warning:
warning: obsolete use of designated initializer without ‘=’
The GCC documentation states the following:
An alternative syntax for this that has been obsolete since GCC 2.5 but GCC still accepts is to write ‘[index]’ before the element value, with no ‘=’.
That's a GNU extension. It was standardized in C99 with slightly different syntax, namely an equal sign between the [index] and the value and no way to specify a range of indices. They are called designated initializers.
The C standard shows an example of probably the most widespread use, provide a string description for enums:
33 EXAMPLE 9 Arrays can be initialized to correspond to the elements of an enumeration by using designators:
enum { member_one, member_two };
const char *nm[] = {
[member_two] = "member two",
[member_one] = "member one",
};
It even allows nifty stuff like
EXAMPLE 11 Designators can be used to provide explicit initialization when unadorned initializer lists might be misunderstood:
struct { int a[3], b; } w[] =
{ [0].a = {1}, [1].a[0] = 2 };
Got a doubt in struct variable assignment.
struct udata
{
char name[50];
int num;
char ch;
};
void main()
{
struct udata a = {"ram", 20, 'a'};
struct udata b;
//b = {"ashok", 10, 'c'}; - illegal
b = a;
}
In above code b = {"ashok", 10, 'c'}; is giving compilation error but its accepting b = a;. I hope both are similar kind of assignment, but I dont know why its not accepting first one. Can someone explain me why it is so ?
Note : I am compiling in a fedora gcc compiler.
Initializers can only be used at declaration time. If you want to initialize b after declaration, then you can do it by using a compound literal-- a C99 feature:
b = (struct udata){"ashok", 10, 'c'};
GCC also support copound literals as an extension.
What you're trying to do cannot be done directly in standard C. The best standard and portable solution is to use a temporary:
const struct udata tmp = {"ashok", 10, 'c'};
b = tmp;
However, in practice, the following is often (but not always!) allowed by compilers (*note below):
b = (struct udata){...};
(* note: I believe at least MSVC does not support this syntax, and probably many others; but just throwing it out there. GCC, however, does support it)
That's how C is designed and specified to work. There's nothing you can do. If you have a structure variable, you can only initialize it by an initializer in the declaration or by later initializing the individual members.
In the future, when posting a question regarding compiler errors, please include the complete and unedited error log in the question.
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++.
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.