Initialization of anonymous struct, workaround for gcc 4.9 - c

I have the following struct types:
typedef struct PG_Point PG_Point;
struct PG_Point
{
int x;
int y;
};
typedef struct PG_Size PG_Size;
struct PG_Size
{
int width;
int height;
};
typedef struct PG_Bounds PG_Bounds;
struct PG_Bounds
{
union
{
struct
{
PG_Point topLeft;
PG_Size size;
};
struct
{
struct
{
int x;
int y;
};
struct
{
int width;
int height;
};
};
};
};
with the following initializers:
#define PG_Point_init(ix, iy) {.x=(ix), .y=(iy)}
#define PG_Size_init(iwidth, iheight) {.width=(iwidth), .height=(iheight)}
#define PG_Bounds_init(ix, iy, iwidth, iheight) { \
.topLeft=PG_Point_init((ix),(iy)), \
.size=PG_Size_init((iwidth),(iheight)) }
From what I understand, it's correct in c11 to initialize the fields of an anonymous struct as if they were directly fields of the containing struct? But with gcc 4.9.2, this gives the following warning:
warning: missing initializer for field ‘size’ of ‘struct <anonymous>’ [-Wmissing-field-initializers]
It works if I change the initializer to this version:
#define PG_Bounds_init(ix, iy, iwidth, iheight) {{{ \
.topLeft=PG_Point_init((ix),(iy)), \
.size=PG_Size_init((iwidth),(iheight)) }}}
That is, explicitly having the union and struct as sub aggregates.
Is this even allowed? Do I have to expect other compilers to reject this?

From what I understand, it's correct in c11 to initialize the fields of an anonymous struct as if they were directly fields of the containing struct?
There are two parts to that. First of all, we need to tackle the question of whether such members can be initialized at all, because Paragraph 6.7.2.1/13 identifies anonymous structure and union members as specific kinds of "unnamed members", and paragraph 6.7.9/9 says
Except where explicitly stated otherwise, for the purposes of this subclause unnamed members of objects of structure and union type do not participate in initialization.
The rest of section 6.7.9 (Initialization) nowhere says anything that I would interpret as explicitly applying to anonymous structure and anonymous union members themselves, but I don't think the intent is to prevent initialization of the named members of anonymous members, especially given that they are considered members of the containing structure or union (see below). Thus, I do not interpret the standard to forbid the initialization you are trying to perform.
So yes, I read C11 to allow your initializer and to specify that it has the effect you appear to intend. In particular, paragraph 6.7.2.1/13 of the standard says, in part,
The members of an anonymous structure or union are considered to be members of the containing structure or union. This applies recursively if the containing structure or union is also anonymous.
Your initializer therefore satisfies the constraint in paragraph 6.7.9/7, that the designators within specify names of members of the current object (in your case, a struct PG_Bounds). The following paragraphs of section 6.7.9 present the semantics for initializers, and I see no reason to interpret them to specify anything other than initialization of the overall object with the values you have provided.
At this point, I reiterate that gcc is issuing a warning, not rejecting your code, and in this case I think the warning is spurious. I wrote a test program such as I suggested in comments that you do, and tried it on gcc 4.8.5 in C11 mode. Although gcc emitted the same warning you presented (but only with -Wextra enabled), I was able to demonstrate that your initializer initialized all members of a subject struct PG_Bounds to the intended values.
You also observe that gcc does not warn if you change the initializer to a version that uses nested brace-enclosed initializers, and ask
Is this even allowed? Do I have to expect other compilers to reject this?
This could be viewed as more problematic with respect to paragraph 6.7.9/9, so in that sense it is perhaps riskier. I am uncertain whether there is any compiler that actually rejects it or does the wrong thing with it. I think the intent of the standard is to allow this initializer, but I would prefer the other form, myself.

Related

Alignment of compound type objects in C90 and C99

Please consider the following types:
typedef struct { char myArray[300]; } MyStruct;
typedef union { char myArray[300]; } MyUnion;
typedef struct { uint64_t x; } MyStruct2;
typedef union { uint64_t x; } MyUnion2;
typedef struct { uint64_t x; char myArray[300]; } MyStruct3;
typedef union { uint64_t x; char myArray[300]; } MyUnion3;
I could find information about alignment and padding of members of compound types but I am not sure about objects of those type itself.
What alignment rules apply to objects of these types in RAM using C90 and C99 on X86 platform? Can the alignment change e.g. because the optimizer removes unused members (especially in unions)?
Alignment of objects is implementation defined. You should use compiler specific attributes if you want to set a specific value.
The compiler cannot reasonably be sure a member is unused, hence will not remove "unused" members from unions or structs (actually, unions are another matter because what would "unused" mean?).
The only situation I can think of when the compiler can be sure, is when only static or automatic variables are created in a compilation unit of a struct, which are never passed to a function outside the compilation unit and one or more members are never used in statements. And probably I forgot something that defeats this reasoning.
I think that in all other cases the compiler cannot be sure a member is not used. For example, if it is passed to a function in another compilation unit the compiler cannot change the definition because the other function will rely on the definition and might be using members not used in this compilation unit.
For a union the compiler can never be sure because the memory of the members is shared.

All struct identifiers are automatically forward declared

While answer warning: assignment from incompatible pointer type for linklist array, I noticed any undeclared identifier perceded with struct keyword are considered as forward declared identifiers.
For instance the program below compiles well:
/* Compile with "gcc -std=c99 -W -Wall -O2 -pedantic %" */
#include <stdio.h>
struct foo
{
struct bar *next; /* Linked list */
};
int main(void) {
struct bar *a = 0;
struct baz *b = 0;
struct foo c = {0};
printf("bar -> %p\n", (void *)a);
printf("baz -> %p\n", (void *)b);
printf("foo -> %p, %zu\n", (void *)&c, sizeof c); /* Remove %zu if compiling with -ansi flag */
return 0;
}
My question: Which rule guides a C compiler to treat undeclared struct identifiers as forward declared incomplete struct types?
The Standard says (6.2.5.28)
All pointers to structure types shall have the same representation and alignment requirements as each other.
This means the compiler knows how to represent the pointers to any structure, even those that are (yet) undefined.
Your program deals only with pointers to such structures, so it's ok.
It is described in 6.2.5 Types and 6.7.2.3 Tags.
struct identifier is an object type.
6.2.5 Types
The meaning of a value stored in an object or returned by a function is determined by the
type of the expression used to access it. (An identifier declared to be an object is the
simplest such expression; the type is specified in the declaration of the identifier.) Types
are partitioned into object types (types that describe objects) and function types (types
that describe functions). At various points within a translation unit an object type may be
incomplete (lacking sufficient information to determine the size of objects of that type) or
complete (having sufficient information). 37)
37) A type may be incomplete or complete throughout an entire translation unit, or it may change states at
different points within a translation unit.
An array type of unknown size is an incomplete type. It is completed, for an identifier of
that type, by specifying the size in a later declaration (with internal or external linkage).
A structure or union type of unknown content (as described in 6.7.2.3) is an incomplete type. It is completed, for all declarations of that type, by declaring the same structure or
union tag with its defining content later in the same scope.
6.7.2.3 Tags
All declarations of structure, union, or enumerated types that have the same scope and
use the same tag declare the same type. Irrespective of whether there is a tag or what
other declarations of the type are in the same translation unit, the type is incomplete 129)
until immediately after the closing brace of the list defining the content, and complete
thereafter.
129) An incomplete type may only by used when the size of an object of that type is not needed. It is not
needed, for example, when a typedef name is declared to be a specifier for a structure or union, or
when a pointer to or a function returning a structure or union is being declared. (See incomplete types
in 6.2.5.) The specification has to be complete before such a function is called or defined.
In addition to the answer provided by 2501, and your comment to it that "In my case, there is not even the forward declaration", the following.
Any use of a struct tag counts as a (forward) declaration of the structure type, if it had not been declared before. Although a more formal way would be to say that this simply counts as a type, since the C standard does not mention "forward declarations of structure types", just complete and incomplete structure types (6.2.5p22).
6.7.2 Type specifiers tells us that a struct-or-union-specifier is a type-specifier, and 6.7.2.1 Structure and union specifiers paragraph 1 tells us that that in turn struct identifier is a struct-or-union-specifier.
Suppose you have a linked list declaration, something like
struct node {
struct node *next;
int element;
};
then the "implicit forward declaration" of this incomplete type is essential for this structure to work. After all, the type struct node is only complete at the terminating semicolon. But you need to refer to it in order to declare the next pointer.
Also, a struct node declaration (of incomplete type) can go out of scope, just like any other declaration. This happens for instance if you have some prototype
int function(struct unknown *parameter);
where the struct unknown goes out of scope immediately at the end of the declaration. Any further declared struct unknowns are then not the same as this one. That is implied in the text of 6.2.5p22:
A structure or union type of unknown content (as described in 6.7.2.3)
is an incomplete type. It is completed, for all declarations of that
type, by declaring the same structure or union tag with its defining
content later in the same scope.
That is why gcc warns about this:
foo.c:1:21: warning: 'struct unknown' declared inside parameter list
foo.c:1:21: warning: its scope is only this definition or declaration, which is probably not what you want
You can fix this by putting an extra forward declaration before it, which makes the scope start earlier (and therefore end later):
struct unknown;
int function(struct unknown *parameter);
I think that the most elegant use-case where incomplete struct types are used is something like this :
struct foo
{
struct bar *left;
struct bar *right;
};
struct bar
{
int something;
struct foo *next;
};
I.e. double recursion, where a points to b and b points to a.
Such cases might be a reason why this feature was included in original C language specification.
Original question is whether all struct identifiers are automatically forward declared. I think that it would be better to say that all incomplete struct definitions are automatically considered as forward declaration.
Edit: Following the comment about documentation, let's look at the C language bible : Kerninghan&Ritchie - The C Programming Language, section "6.5 Self-referential Structures" says :
Occasionally, one needs a variation of self-referential structures:
two structures that refer to each other. The way to handle this is:
struct t {
...
struct s *p; /* p points to an s */
};
struct s {
...
struct t *q; /* q points to a t */
};
I agree, that it is possible to implement another way, but I would take this as good motivation from authors of the C language and I agree with them that it is elegant way to implement this.

Union of structs with common first member

I am unsure of whether or not the code has pointer aliasing (or other standard conformance issues) in the asserts cast. It seems that a pointer to the union type should be able to be cast to a pointer of the first member and since the union is only composed of these two structs, I think a cast to the first member should work, but I'm not sure if this is correct or if I'm glossing over padding details in the process. Are unions required to pad the upper bits?
It seems as this is unspecified behavior? Does anyone have any insight as to whether this is suported. I know that there is an alternative standard way of doing this by using a struct with a enum type field and struct container_storage member, but it seems like a waste of space considering that this information is already in struct contained
compilation command in linux: gcc -std=c99 -Wextra -pedantic -fstrict-aliasing test.c && ./a.out && echo $? returns 0
#include <stdlib.h>
#include <assert.h>
enum type {type_a = 1, type_b = 2};
struct contained {
int some_other_field;
enum type type;
};
struct container_a {
struct contained contained;
int test;
};
struct container_b {
struct contained contained;
char test;
};
union container_storage {
struct container_a container_a;
struct container_b container_b;
};
int
main(int argc, char **argv)
{
union container_storage a =
{.container_a = {.contained = {.type = type_a}, .test = 42}};
union container_storage b =
{.container_b = {.contained = {.type = type_b}, .test = 'b'}};
assert(((struct contained *)&a)->type == type_a);
assert(((struct contained *)&b)->type == type_b);
return EXIT_SUCCESS;
}
References:
[1] gcc, strict-aliasing, and casting through a union
[2] What is the strict aliasing rule?
That should be fine. C11, 6.5.2.3/6 ("Structure and union members") says:
One special guarantee is made in order to simplify the use of unions: if a union contains
several structures that share a common initial sequence (see below), and if the union
object currently contains one of these structures, it is permitted to inspect the common
initial part of any of them anywhere that a declaration of the completed type of the union
is visible. Two structures share a common initial sequence if corresponding members
have compatible types (and, for bit-fields, the same widths) for a sequence of one or more
initial members.
(C++ makes the same guarantee (C++11, 9.2/18) for standard-layout unions.)
union don't pad, they just overlay their members. The first member of any struct is guaranteed to start right off, without padding. In general struct that start with the same members of same type are guaranteed to have the same layout for that initial part.
Under C89, a pointer of structure type which identifies a member of a union may be used to inspect any member which is part of a Common Initial Sequence shared with the type of data stored therein. This in turn generally implies that a pointer to any structure type could be used to inspect any member of the Common Initial Sequence shared with any other type (such behavior would have been unambiguously defined if the object happened to be a member of a declared union object, and the only practical way for a compiler to yield the required behavior in those cases would be to uphold it for all).
C99 added an additional requirement that the CIS guarantees only apply when a complete union type containing both structures is visible, which some compiler writers seem to think means it only applies to accesses performed directly through union types. The authors of such compilers seem to think a function that would need to handle functions with a common header like:
struct smallThing { void *next; uint16_t length; uint8_t dat[2]; };
struct bigThing { void *next; uint16_t length; uint8_t dat[65528]; };
should be to extract out the header like:
struct uHeader { void *next; uint16_t length; };
struct smallThing { uHeader head; uint8_t dat[2]; };
struct bigThing { uHeader head; uint8_t dat[15994]; };
or use union-type objects for everything, even though using uHeader would
increase the size of struct smallThing by 50% (and totally break any code that
had been reliant upon its layout), and using unions for everything when most objects only need to be small would increase memory usage a thousandfold.
If one needs code to be compatible with compilers that essentially ignore the Common Initial Sequence rule, one should regard the Common Initial Sequence rule as essentially useless. Personally, I think it would be better to document that only compilers that honor the CIS should be considered suitable for use with one's code, rather than bending over backward to accommodate unsuitable compilers, but I think it's important to be aware that compilers like the latter ones exist.
So far as I can tell, clang and gcc do not honor the CIS rule in any useful way except when the -fno-strict-aliasing flag is set. I don't know about other compilers.

Why do these C struct definitions give warnings and errors?

Why do these two struct definitions compile fine:
struct foo {
int a;
} __attribute__((packed));
typedef struct __attribute__((packed)) {
int a;
} bar;
While this one gives a warning:
typedef struct {
int a;
} baz __attribute__((packed));
warning: ‘packed’ attribute ignored [-Wattributes]
And this one gives an error and a warning:
typedef struct qux __attribute__((packed)) {
int a;
} qux;
error: expected identifier or ‘(’ before ‘{’ token
warning: data definition has no type or storage class [enabled by default]
As a novice C programmer, the fact that the last two definitions don't work seems like a fairly arbitrary choice on the parts of the language designers/compiler writers. Is there a reason for this? I'm using gcc 4.7.3.
typedef struct __attribute__((packed)) {
int a;
} bar;
vs
typedef struct {
int a;
} baz __attribute__((packed));
In the first you said "consider this anonymous structure, with the attribute packed, that has a member a. then create an alias for this structure, and name that 'bar'". The normal syntax for describing a struct without doing it anonymously and having to typedef it is
struct bar { int a; };
in the second declaration you said "consider this anonymous structure, that has a member a. then create an alias for this structure, and name that 'baz who is packed'".
It doesn't work because you're trying to apply the attribute to the alias in a typedef, not to the structure definition.
typedef <entity> <alias>;
I would advise putting on a hit on whomever suggested you use the "typedef" syntax for describing structs :)
The reason that it works in the first two instances is because __attribute__((packed)) can only be applied to a struct, union or enum. In the first example, you're declaring a struct called foo, in the second you are declaring a struct called bar. In this second example, typedef converts a declaration of a variable into a declaration of a type.
Your third example is declaring a variable called baz and trying to declare it as packed. Since packing info is attached to the type, not an instance, this makes no sense, and the compiler ignores it.
Here are details on how attributes work in gcc.
You really shouldn't be even using packed unless you know exactly what you are doing. For one thing, __attribute__ is not standard C. If is a gcc extension and so won't work with any other compiler.
For another, there are very few situations where it is actually needed. In your code above, for instance, it is a no-op even in the first two instances as packing removes space between members, and you've only got one member in each struct. The reason that packing structures isn't the default is because common datatypes just work better when aligned on a certain boundary. For instance, access to an int will perform better if aligned on a memory location that is a multiple of four. See the wiki entry on data structure alignment for more information.
The keyword __attribute__((packed)) applies to struct.
In
typedef struct {
int a;
} baz __attribute__((packed));
typedef associates baz with the struct - the attributes comes after, and applies to nothing - gcc ignores it. To fix this, allow typedef to associate the whole struct declaration, including the attribute, by placing baz after the attribute:
typedef struct {
int a;
} __attribute__((packed)) baz;
In the 2nd example, the struct declaration is wrong
struct qux __attribute__((packed)) {
int a;
}
as quz should appear after the attribute:
struct __attribute__((packed)) qux {
int a;
}
It is usually better to let the compiler optimizes the structure and align the inner elements in memory in a way the CPU processes them more efficiently.
Packing a structure, however, may be important at times when building a data structure that has to be packed, in order to cope, for instance, with a driver demands.
This is a rather odd question because it's all very well explained in the manual. However to there isn't anything arbitrary about it, you're just not exploring the complete use of this built-in keyword:
__attribute__(()) is a general purpose gcc extension. There are function attributes, type attributes and variable attributes.
Where you place the word __attribute__ determines what it applies to. You could potentially have several __attribute__s in a given declaration so it's not arbitrary to make some of it syntactically unacceptable for easier internal parsing.

What is the size of an empty struct in C?

According to me, it is zero but there seems to be bit confusion here
I have tested it with gcc compiler and it gives me zero as output. I know that in C++, size of an empty class is 1. Let me know if I am missing anything here.
A struct cannot be empty in C because the syntax forbids it. Furthermore, there is a semantic constraint that makes behavior undefined if a struct has no named member:
struct-or-union-specifier:
struct-or-union identifieropt { struct-declaration-list }
struct-or-union identifier
struct-or-union:
struct
union
struct-declaration-list:
struct-declaration
struct-declaration-list struct-declaration
struct-declaration:
specifier-qualifier-list struct-declarator-list ;
/* type-specifier or qualifier required here! */
specifier-qualifier-list:
type-specifier specifier-qualifier-listopt
type-qualifier specifier-qualifier-listopt
struct-declarator-list:
struct-declarator
struct-declarator-list , struct-declarator
struct-declarator:
declarator
declaratoropt : constant-expression
If you write
struct identifier { };
It will give you a diagnostic message, because you violate syntactic rules. If you write
struct identifier { int : 0; };
Then you have a non-empty struct with no named members, thus making behavior undefined, and not requiring a diagnostic:
If the struct-declaration-list contains no named members, the behavior is undefined.
Notice that the following is disallowed because a flexible array member cannot be the first member:
struct identifier { type ident[]; };
The C grammar doesn't allow the contents of a struct to be empty - there has to be at least an unnamed bitfield or a named member (as far as the grammar is concerned - I'm not sure if a struct that contains only an unnamed bitfield is otherwise valid).
Support for empty structs in C are an extension in GCC.
In C++ and empty struct/class member-specification is explicitly permitted, but the size is defined to be 1 - unless as part of the empty base optimization the compiler is allowed to make an empty base class take no space in the derived class.
In C99: "If the struct-declaration-list contains no named members, the behavior is undefined."
The syntax doesn't really allow it anyway, though I don't see anything that says a diagnostic is required, which puts it pretty much back in the "undefined behavior" camp.
on VC 8 It gives error if we try to get the sizeof empty struct, on the other way round on linux with gcc it gives size 1 because it uses gcc extention instead of c language specification which says this is undefined behaviour.
struct node
{
// empty struct.
};
int main()
{
printf("%d", sizeof(struct node));
return 0;
}
on windows vc 2005 It gives compilation error
on linux with gcc it gives size 1 because gcc extension
http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Empty-Structures.html#Empty-Structures
(As Pointed out by Michael Burr)

Resources