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
Related
Just curious, what actually happens if I define a zero-length array int array[0]; in code? GCC doesn't complain at all.
Sample Program
#include <stdio.h>
int main() {
int arr[0];
return 0;
}
Clarification
I'm actually trying to figure out if zero-length arrays initialised this way, instead of being pointed at like the variable length in Darhazer's comments, are optimised out or not.
This is because I have to release some code out into the wild, so I'm trying to figure out if I have to handle cases where the SIZE is defined as 0, which happens in some code with a statically defined int array[SIZE];
I was actually surprised that GCC does not complain, which led to my question. From the answers I've received, I believe the lack of a warning is largely due to supporting old code which has not been updated with the new [] syntax.
Because I was mainly wondering about the error, I am tagging Lundin's answer as correct (Nawaz's was first, but it wasn't as complete) -- the others were pointing out its actual use for tail-padded structures, while relevant, isn't exactly what I was looking for.
An array cannot have zero size.
ISO 9899:2011 6.7.6.2:
If the expression is a constant expression, it shall have a value greater than zero.
The above text is true both for a plain array (paragraph 1). For a VLA (variable length array), the behavior is undefined if the expression's value is less than or equal to zero (paragraph 5). This is normative text in the C standard. A compiler is not allowed to implement it differently.
gcc -std=c99 -pedantic gives a warning for the non-VLA case.
As per the standard, it is not allowed.
However it's been current practice in C compilers to treat those declarations as a flexible array member (FAM) declaration:
C99 6.7.2.1, §16: As a special case, the last element of a structure with more than one named member may have an incomplete array type; this is called a flexible array member.
The standard syntax of a FAM is:
struct Array {
size_t size;
int content[];
};
The idea is that you would then allocate it so:
void foo(size_t x) {
Array* array = malloc(sizeof(size_t) + x * sizeof(int));
array->size = x;
for (size_t i = 0; i != x; ++i) {
array->content[i] = 0;
}
}
You might also use it statically (gcc extension):
Array a = { 3, { 1, 2, 3 } };
This is also known as tail-padded structures (this term predates the publication of the C99 Standard) or struct hack (thanks to Joe Wreschnig for pointing it out).
However this syntax was standardized (and the effects guaranteed) only lately in C99. Before a constant size was necessary.
1 was the portable way to go, though it was rather strange.
0 was better at indicating intent, but not legal as far as the Standard was concerned and supported as an extension by some compilers (including gcc).
The tail padding practice, however, relies on the fact that storage is available (careful malloc) so is not suited to stack usage in general.
In Standard C and C++, zero-size array is not allowed..
If you're using GCC, compile it with -pedantic option. It will give warning, saying:
zero.c:3:6: warning: ISO C forbids zero-size array 'a' [-pedantic]
In case of C++, it gives similar warning.
It's totally illegal, and always has been, but a lot of compilers
neglect to signal the error. I'm not sure why you want to do this.
The one use I know of is to trigger a compile time error from a boolean:
char someCondition[ condition ];
If condition is a false, then I get a compile time error. Because
compilers do allow this, however, I've taken to using:
char someCondition[ 2 * condition - 1 ];
This gives a size of either 1 or -1, and I've never found a compiler
which would accept a size of -1.
Another use of zero-length arrays is for making variable-length object (pre-C99). Zero-length arrays are different from flexible arrays which have [] without 0.
Quoted from gcc doc:
Zero-length arrays are allowed in GNU C. They are very useful as the last element of a structure that is really a header for a variable-length object:
struct line {
int length;
char contents[0];
};
struct line *thisline = (struct line *)
malloc (sizeof (struct line) + this_length);
thisline->length = this_length;
In ISO C99, you would use a flexible array member, which is slightly different in syntax and semantics:
Flexible array members are written as contents[] without the 0.
Flexible array members have incomplete type, and so the sizeof operator may not be applied.
A real-world example is zero-length arrays of struct kdbus_item in kdbus.h (a Linux kernel module).
I'll add that there is a whole page of the online documentation of gcc on this argument.
Some quotes:
Zero-length arrays are allowed in GNU C.
In ISO C90, you would have to give contents a length of 1
and
GCC versions before 3.0 allowed zero-length arrays to be statically initialized, as if they were flexible arrays. In addition to those cases that were useful, it also allowed initializations in situations that would corrupt later data
so you could
int arr[0] = { 1 };
and boom :-)
Zero-size array declarations within structs would be useful if they were allowed, and if the semantics were such that (1) they would force alignment but otherwise not allocate any space, and (2) indexing the array would be considered defined behavior in the case where the resulting pointer would be within the same block of memory as the struct. Such behavior was never permitted by any C standard, but some older compilers allowed it before it became standard for compilers to allow incomplete array declarations with empty brackets.
The struct hack, as commonly implemented using an array of size 1, is dodgy and I don't think there's any requirement that compilers refrain from breaking it. For example, I would expect that if a compiler sees int a[1], it would be within its rights to regard a[i] as a[0]. If someone tries to work around the alignment issues of the struct hack via something like
typedef struct {
uint32_t size;
uint8_t data[4]; // Use four, to avoid having padding throw off the size of the struct
}
a compiler might get clever and assume the array size really is four:
; As written
foo = myStruct->data[i];
; As interpreted (assuming little-endian hardware)
foo = ((*(uint32_t*)myStruct->data) >> (i << 3)) & 0xFF;
Such an optimization might be reasonable, especially if myStruct->data could be loaded into a register in the same operation as myStruct->size. I know nothing in the standard that would forbid such optimization, though of course it would break any code which might expect to access stuff beyond the fourth element.
Definitely you can't have zero sized arrays by standard, but actually every most popular compiler gives you to do that. So I will try to explain why it can be bad
#include <cstdio>
int main() {
struct A {
A() {
printf("A()\n");
}
~A() {
printf("~A()\n");
}
int empty[0];
};
A vals[3];
}
I am like a human would expect such output:
A()
A()
A()
~A()
~A()
~A()
Clang prints this:
A()
~A()
GCC prints this:
A()
A()
A()
It is totally strange, so it is a good reason not to use empty arrays in C++ if you can.
Also there is extension in GNU C, which gives you to create zero length array in C, but as I understand it right, there should be at least one member in structure prior, or you will get very strange examples as above if you use C++.
This question already has answers here:
Can a const variable be used to declare the size of an array in C?
(5 answers)
Closed 6 years ago.
In C the const qualifier makes an object read-only but not a constant expression. For example, it is not possible to use a const int variable to dimension an array:
const int n = 10;
int arr [n]; /* Compile-time error */
Which is the technical reason for this? Is it not possible for the compiler at compile-time to know that the object has actually a constant value?
I don't think that my question is an exact duplicate of Can a const variable be used to declare the size of an array in C?
because I'm not asking if that's possible (it is clearly stated in my question that it is not) but the technical reason why it's not possible.
After the comment of Olaf below, this answer and some musings I would try to summarize and answer my question in this way:
In C a const object is not a compile-time constant because it can violate both requirements:
First, it is possible to initialize the const object at runtime as in:
int i;
scanf ("%d", & i);
const int n = i;
so here we violate the requirement of "known at compile-time".
Secondly, as Olaf pointed out, the const qualifier means that the program itself will not modify the value of the object after the declaration-initialization. But the value of the object in memory could still be modified by some other entity outside the program itself, so here we are not guaranteeing the requirement of actual constness.
Please criticize if this answer is incorrect or incomplete.
One technical reason for this is probably that such a declaration is even valid when the initializer is not a constant expression, so this is a semantic property that is deduced from looking at the initializer.
Then, with the current rules there is no way to have such a thing in a header file to be declared and defined in file scope. Any object can only have one definition, and several object files could not be linked together.
There are ideas to improve that situation for the next version of C.
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.
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++.
This question already has answers here:
Error "initializer element is not constant" when trying to initialize variable with const
(8 answers)
Closed 7 years ago.
The following code wont compile:
const int a = 0;
struct Test
{
int b;
};
static const struct Test test =
{
a
};
Its a cut down example of what I am really trying to do, but what am I doing wrong?
In C89/90 version of C language all aggregate initializers must consist of constants only. In C language terminology a constant of int type is a literal value, like 10, 20u, 0x1 etc. Enum members are also constants. Variables of const int type are not constants in C. You can't use a const int variable in aggregate initializer. (For this reason, in C language, when you need to declare a named constant you should use either #define or enum, but not const qualifier.)
In C99 this requirement for aggregate initializers was relaxed. It is now OK to use non-constants in aggregate initializers of local objects. However, for static objects (as in your example) the requirement still holds. So, even in C99 you'l' have to either use
#define a 0
or use a named enum constant as suggested in #R..'s answer.
a is not a constant expression. It's a const-qualified variable. If you want a symbolic name that you can use in constant expressions, you need either a preprocessor macro (#define a 0) or an enum (enum { a = 0 };).