I've run into a problem that seems to not be addressed by any of the C Standards after C89 save for the mention that structures initialization limits had been lifted. However, I've run into an error using the Open Watcom IDE (for debugging) where the compiler states that the initializer must be a constant expression.
Here's the gist of what's going on.
typedef struct{
short x;
short y;
} POINT;
void foo( short x, short y )
{
POINT here = { x, y }; /* <-- This is generating the error for the compiler */
/* ... */
}
Any ideas why, or what standard disallows that?
The following quote is from the C99 rationale:
The C89 Committee considered proposals for permitting automatic
aggregate initializers to consist of a brace-enclosed series of
arbitrary execution-time expressions, instead of just those usable for
a translation-time static initializer. Rather than determine a set of
rules which would avoid pathological cases and yet not seem too
arbitrary, the C89 Committee elected to permit only static
initializers. This was reconsidered and execution-time expressions are
valid in C99.
The problem is that C isn't an Object language and only does strict typing. Further, C maintains a difference between structs and arrays.
The way your code will have to work is
void foo( short x, short y )
{
POINT here;
here.x = x;
here.y = y;
}
This is normal for C89... initializers do need to be constant, ie. able to be determined at compile time. This means no variables in initializers, and it's true for other types as well, not just structs. In C99, your code would work.
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++.
I'm using Keil uVision to compile this code for an embedded project.
void doSomething(void)
{
unsigned char a = 0x01;
unsigned char b = 0x02;
typedef struct
{
void *pVoid;
} test_t;
test_t t[] = {{&a}, {&b}};
}
On the last line I receive an error
error: #28: expression must have a constant value
I've read that this is an issue where the compiler does not know the size of the variable. I don't understand what that means.
The variables a and b are of a defined type, so their pointers will always be the same size? Regardless of their type, this is embedded so pointers are all the same size?
It works to make var a and b static, why? This being embedded, I don't want the memory allocated continuously so that is not a solution here.
UPDATE:
I'm using Keil uVision 4.72.10.0 with Armcc v5.03.0.76 - I was able to get Keil to compile this, using the "--c99" flag, as found here.
Your function is perfectly fine in modern C, or even in C99, but C90 had stricter rules for initializers, and your code does not comply with those.
Here is the relevant provision of C90:
All the expressions in an initializer for an object that has static
storage duration or in an initializer list for an object that has
aggregate or union type shall be constant expressions.
(C90 6.5.7/4; emphasis added)
Structure types are aggregate types, so that applies to your code (when interperted according to C90). Where a and b identify function-scope variables, the expressions &a and &b are not constant expressions, so your code does not conform (to C90).
C99 drops the bit about aggregate or union type, and C2011 adds a provision for objects with thread storage duration (new in that version of C) to yield:
All the expressions in an initializer for an object that has static or
thread storage duration shall be constant expressions or string
literals.
That does not apply to your code.
It seems, then, that your compiler is enforcing C90 rules. Perhaps there is an option to select a more recent standard, but if not, then your best alternative is probably to set the structure members' values with assignment statements instead of an initializer:
test_t t[2];
t[0].pVoid = &a;
t[1].pVoid = &b;
This is my code:
#include <stdio.h>
typedef struct {
const char *description;
float value;
int age;
} swag;
typedef struct {
swag *swag;
const char *sequence;
} combination;
typedef struct {
combination numbers;
const char *make;
} safe;
int main(void)
{
swag gold = { "GOLD!", 100000.0 };
combination numbers = { &gold, "6503" };
safe s = { numbers, "RAMCON" };
printf("Contents = %s\n", s.numbers.swag->description);
getchar();
return 0;
}
Whenever I compile it with the VS developer console, I get this error: error C2440: 'initializing' : cannot convert from 'combination' to 'swag *'.
However if I use gcc the console just prints: "GOLD!". Don't understand what's going on here.
What you stumbled upon is an implementation-specific variant of a popular non-standard compiler extension used in various C89/90 compilers.
The strict rules of classic C89/90 prohibited the use of non-constant objects in {} initializers. This immediately meant that it was impossible to specify an entire struct object between the {} in the initializer, since that would violate the above requirement. Under that rule you could only use scalar constants between the {}.
However, many C89/90 compilers ignored that standard requirement and allowed users to specify non-constant values when writing {} initializers for local objects. Unfortunately, this immediately created an ambiguity if user specified a complex struct object inside the {} initializer, as in your
safe s = { numbers, "RAMCON" };
The language standard did not allow this, for which reason it was not clear what this numbers initializer should apply to. There are two ways to interpret this:
The existing rules of the language said that the compiler must automatically enter each level of struct nesting and apply sequential initializers from the {} to all sequential scalar fields found in that way (actually, it is a bit more complicated, but that's the general idea).
This is exactly what your compiler did. It took the first initializer numbers, it found the first scalar field s.numbers.swag and attempted to apply the former to the latter. This expectedly produced the error you observed.
Other compiler took a more elaborate approach to that extension. When the compiler saw that the next initializer from the {} list had the same type as the target field on the left-hand side, it did not "open" the target field and did not enter the next level of nesting, but rather used the whole initializer value to initialize the whole target field.
This latter behavior is what you expected in your example (and, if I am not mistaken, this is the behavior required by C99), but your C89/90 compiler behaved in accordance with the first approach.
In other words, when you are writing C89/90 code, it is generally OK to use that non-standard extension when you specify non-constant objects in local {} initializers. But it is a good idea to avoid using struct objects in such initializers and stick to scalar initializers only.
Looks like an issue with the initializers. If you use the proper options with gcc, it will tell you this:
$ gcc -Wall -ansi -pedantic x.c
x.c: In function ‘main’:
x.c:21: warning: initializer element is not computable at load time
x.c:22: warning: initializer element is not computable at load time
which is propably the same issue VS is trying to tell you. You can make these go away if you declare gold and numbers static.
Can someone explain this behavior?
Using the compiler flag std=c99 I get the following errors:
"initializer element is not constant" for b1.
"expected expression before '.' token" for b2
b3 is OK.
When not using -std=c99 all lines are OK.
When not using static b1 is ok.
I'm using GCC.
typedef struct A_tag {
int v;
int w;
} A;
typedef struct B_tag {
A super;
int x;
int y;
} B;
void test(){
static B b1 = ((B){.super={.v=100}, .x=10});
static B b2 = ({.super={.v=100}, .x=10});
static B b3 = {.super={.v=100}, .x=10};
}
(B){.super={.v=100}, .x=10} is not a "cast" but as a whole this is a "compound literal" a temporary object that only lives inside the corresponding expression (basically). Since this is not a constant but a temporary object, by the standard you can't initialize with it.
As stated above, this is a "compound literal". Whether it can be used for initialization is actually implementation defined, IMO. The C11 standard says in [6.7.9 §4] that "expressions in an initializer for an object that has static or thread storage duration shall be constant expressions or string literals". Then in [6.6 §7] it lists what constant expressions can be and [6.6 §10] it allows an implementation to "accept other forms of constant expressions".
Since a "compound literals" is constant by definition, it ought to be possible to use it for initialization, although the standard does not explicitly say so. (And many compilers do accept it.)
Reading the C11 standard (actually N1570 which is a late draft), you will see that the rules for initializers of objects of static storage duration are different from the rules for those of automatic storage duration.
As I read it, compound literals can only be used for initializers of objects of automatic storage duration. They are allowed by 6.7.9 paragraph 13.
I wonder why the following does not work with Visual studio
typedef struct {
float x, y;
} complexf;
typedef union {
complexf f;
long long d;
} rope;
int main(void)
{
complexf a;
rope z = {a};
}
The error is at line rope z = {a}, cannot convert from complexf to float. If the first member of the union is not a typedef, then it works. Is this a compiler bug, or a dark edge of C ?
ANSI C standard (aka C89), 3.5.7:
All the expressions in an initializer
for an object that has static storage
duration or in an initializer list for
an object that has aggregate or union
type shall be constant expressions.
The latter part of this restriction has been dropped in C99, which isn't properly supported by VS.
in VS 6.0 when I compile with /W4 I get
warning C4204: nonstandard extension used : non-constant aggregate initializer
so that makes me think it's not standard C and you are in compiler dependent land.
Works fine on my G++ 3.4.4 on Cygwin.
Except for the ':' at the end needing a change to ';'.
And, I changed '__int64' to 'long long'.
With my stronger bias towards C for such code, I would have written,
rope z = *(rope *)&a;
to force it on to the C++ compiler :-).
But, don't do that...
The right way to go is of course, as David notes in his comment,
rope z; z.f = a;