Using non standard declaration of array in C - c

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 };

Related

Why does splint suggest that { 0 } doesn't really initialize all elements to zero in C: Initializer does not define all elements of a declared array

In this piece of code (the whole file contains only one line):
char buffer[256] = { 0 };
Checked with Splint, I got the following hint:
foo.c(1,20): Initializer block for buffer has 1 element, but declared as char
[256]: 0
Initializer does not define all elements of a declared array. (Use
-initallelements to inhibit warning)
Initializer does not define all elements of a declared array. This is puzzling: I read some SO answers, but all of them claims that { 0 } does initialize all elements to zero.
Splint version:
Splint 3.1.1 --- 12 April 2003
Maintainer: splint-bug#splint.org
Compiled using Microsoft Visual C++ 6.0
Downloaded from Splint.org.
Yes, it does zero all the elements. The general rule is that if you provide less initializers than there are elements, the remaining elements are zeroed. (So e.g. char buffer[256] = {1}; will set only the first element to 1, and the rest to 0.)
The warning doesn't say that remaining elements are uninitialized, it says you didn't provide initializers for them. This warning doesn't make sense in this specific case (= {0} is a common pattern to zero an array), but in general it could be useful (e.g. it would warn about int arr[4] = {1,2,3};).
For char array like that, the most common (and safe) way seems to be:
char buffer[256] = "";
It may be initialised using empty {} just like other struct types:
char buffer[256] = {}; // not working in C, only work for C++
Using {0} seems to be more C++ way to initialise struct type.

extern declaration 2D array in C?

If I define a simple array :
int tableint[][2] = {
{1, 2},
{2, 4},
{3, 9},
{4, 16},
{5, 25}
};
and code in the very same file as :
printf("Value = %d\n",sizeof(tableint));
printf("Value = %d\n",sizeof(tableint[0]));
printf("Num of rows = %d\n",sizeof(tableint)/sizeof(tableint[0]));
Output is as expected:
Value = 40
Value = 8
Num of rows = 5
But if I move the same 'tableint' 2D array in a separate file and retain above mentioned print statements in the previous main file but just adding an extern as follows:
extern int tableint[][2];
I get an error in the following line:
printf("Value = %d\n",sizeof(tableint));
as : invalid application of 'sizeof' to incomplete type 'int[][2]'
I am curious to know why it worked when the 2D array was there within the same file and not when I moved it into another file?
And, the error gets resolved if I define the extern as:
extern int tableint[5][2];
Is there any way where I don't need to mention the number of rows in extern here?
An array declared in this fashion - with [] in the declaration - will have complete type if and only if the declaration includes an initializer. Without an initializer the type is incomplete.
That's your difference that made it work in the first case.
If you really need to declare it as extern, then you have no choice but to specify all sizes explicitly, as long as you require this sizeof technique to work (or as long as you want to see the array size as a constant expression).
If you don't care about being able to use that sizeof trick and if you'd be happy with seeing the array size as run-time value, then you could export it from that "separate file" as another variable or as function.
This is because C source files are treated as separate, individual translation units, than can be compiled independent to each other (for instance with gcc -c ...). The information stored in some unit is not accesssible to another one until linkage phase is concerned.
With that said, the spec is clear that you cannot take sizeof operator for an incomplete type, as N1570 6.5.3.4/1 The sizeof and _Alignof operators says:
The sizeof operator shall not be applied to an expression that has
function type or an incomplete type, to the parenthesized name of such
a type, or to an expression that designates a bit-field member.

C array of structs declaration

In the Linux kernel, I see a declaration of an array of structs that looks like this
struct SomeStructName [] ={
[SOMEWEIRD_NAME] = {
.field1 = "some value"
},
[SOMEWEIRD_NAME2] = {
.field1 = "some value1"
},
}
I have never seen a declaration like that, specifically I can't figure out what [SOMEWEIRD_NAME] means, and why it's used.
It's a C99 designated initializer for arrays.
For example:
/*
* Initialize element 0 to 1
* 1 to 2
* 2 to 3
* 255 to 1
* and all other elements to 0
*/
int arr[256] = {[0] = 1, 2, 3, [255] = 1};
It allows you to initialize some specific array elements in any order and also allows you to omit some elements.
In your example the expression between [] can be a macro name for an integer constant expression or an enum constant. It cannot be a variable name as it has to be an integer constant expression.
Im not sure what you meant but i assume SOMEWEIRD_NAME is a Define value.
Define is a way to give values another name but it wont take space in you'r memorry on runtime, insted, it will be replaced everywhere the name of that defined values is writen in your code during compiling prosses.
The syntax for deifne is as the following: #define NAME_OF_DEFINE 80
in the following example every NAME_OF_DEFINE in your code will be replaced whit the values 80. Notice that you shouldn't end the line whit ;.
In your example i expect SOMEWEIRD_NAME to have a numbric value to set the array's size.
You can fine more information about #define here
The "SOMEWEIRD_NAME" is most likely either a #define whose value is a number, or it's an enumeration, whose numeric value is its position in the enumeration.

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++.

What is tagged structure initialization syntax?

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.

Resources