I'm trying to pass a struct by reference but no matter what I do I'm running into errors. I think I have the prototyping and declaration and the pointers all screwed up.
This is for an Arduino project of mine. The code works fine on the Arduino compiler but doesn't compile on Pelles C compiler.
#include <stdio.h>
#include <string.h>
#include <stdint.h>
void Fault_Bits_To_Flags(uint8_t Master_Fault_Byte, struct Fault_Flag_Struct *Fault_Flag);
struct Fault_Flag_Struct {
char Fault_Name[30];
uint8_t Fault_State;
};
struct Fault_Flag_Struct Fault_Flag [7];
int main(void) {
uint8_t Master_Fault_Byte = 181;
strcpy(Fault_Flag[0].Fault_Name, "fault 0");
Fault_Flag[0].Fault_State = 1;
strcpy(Fault_Flag[1]....
strcpy(Fault_Flag[2]....
strcpy(Fault_Flag[3]....
strcpy(Fault_Flag[4]....
Fault_Bits_To_Flags( Master_Fault_Byte, *Fault_Flag);
return 0;
}
//Puts 8 bits from single byte into 8 separate bytes (flags)//
void Fault_Bits_To_Flags(uint8_t Master_Fault_Byte, struct Fault_Flag_Struct *Fault_Flag) {
for ( int i = 0; i < 8; i++ )
{
Fault_Flag[i].Fault_State = (Master_Fault_Byte >> i) & 1;
}
}
error #2140: Type error in argument 2 to 'Fault_Bits_To_Flags';
expected '(incomplete) struct Fault_Flag_Struct *' but found 'struct
Fault_Flag_Struct'.
error #2120: Redeclaration of 'Fault_Bits_To_Flags', previously
declared at Reference.c(4); expected 'void function(unsigned char,
(incomplete) struct Fault_Flag_Struct *)' but found 'void
function(unsigned char, struct Fault_Flag_Struct )'.
Error code: 1 *
The scope of a parameter declaration in the list of parameters of a function prototype terminates at the end of the function declarator. Opposite to C++ there is no such a notion as the elaborated type specifier in C.
From the C Standard (6.2.1 Scopes of identifiers)
... If the declarator or type specifier that declares the identifier appears
within the list of parameter declarations in a
function prototype (not part of a function definition), the identifier
has function prototype scope, which terminates at the end of the
function declarator
So the type specifier struct Fault_Flag_Struct used in the function prototype
void Fault_Bits_To_Flags(uint8_t Master_Fault_Byte, struct
Fault_Flag_Struct *Fault_Flag);
denotes a different entity compared with the declaration that follows the function prototype
struct Fault_Flag_Struct {
char Fault_Name[30];
uint8_t Fault_State;
};
So you have to exchange the placements of the declarations.
Also this call
Fault_Bits_To_Flags( Master_Fault_Byte, *Fault_Flag);
is invalid because the type of the expression *Fault_Flag is struct Fault_Flag_Struct while the function expects the type struct Fault_Flag_Struct *. That is instead of a pointer to an object of the type struct Fault_Flag_Struct you are passing the object itself.
Scope and Structure Types
There are two problems in the code shown.
The first is because C has some odd rules about structure definitions. One rule, in C 2018 6.7.2.3 4, is that structure declarations with the same tag (the name after struct) declare the same type (a structure type with that name) only if they have the same scope:
All declarations of structure, union, or enumerated types that have the same scope and use the same tag declare the same type.…
When you declare a structure inside a function declaration, like this:
void foo(struct X *p);
Then the scope of X is function prototype scope. Per 6.2.1 4, this scope ends at the end of the function declaration. Then, when you later define the structure, as with:
struct X { int q; }
it is in a different scope, and, per the rule above, the struct X in the function declaration is not the same type as the struct X in the later definition. One way to fix this is to move the structure definition prior to the function declaration. It also suffices merely to declare the structure tag prior to the function declaration, as with:
struct X;
void foo(struct X *p);
To fully understand what is happening here, we should consider two other issues. One issue is that we could have struct X in two different translation units (different source files compiled separately), and calling a function defined with a struct X * parameter in one unit from another unit that defines struct X is allowed. This is because that, although the two struct X types in the two translations units are different, they are compatible. 6.2.7 1 says:
… Moreover, two structure, union, or enumerated types declared in separate translation units are compatible if…
Oddly, this rule only applies to structures declared in separate translation units. If we defined void foo(struct X *p { … } prior to defining struct X in one translation unit, they are different and incompatible types, but, if we define them in separate units, they are compatible types!
The second issue is how can this code work when the structure declarations have separate scopes:
struct X;
void foo(struct X *p);
The first struct X has file scope (per 6.2.1 4), and the second struct X has function prototype scope. The rule in 6.7.2.3 4 only applies if the declarations have the same scope, so it does not say these declare the same struct X. Instead, there is another rule, in 6.7.2.3 9:
If a type specifier of the form struct-or-union identifier or enum identifier occurs other than as part of one of the above forms, and a declaration of the identifier as a tag is visible, then it specifies the same type as that other declaration, and does not redeclare the tag.
(The “above forms” are definitions or stand-alone declarations.) This causes the struct X in the function declaration after a prior file-scope struct X to specify the same type.
Error in Argument
The second error is in the second argument passed to the function in this statement:
Fault_Bits_To_Flags( Master_Fault_Byte, *Fault_Flag);
Fault_Flag is an array, so *Fault_Flag is the first element of the array. This is a structure, not a pointer. To pass a pointer to the first element of the array, use:
Fault_Bits_To_Flags( Master_Fault_Byte, Fault_Flag);
Related
In the following example:
#include <stdio.h>
#include <stdlib.h>
struct B b;
struct B{int a;};
struct B;
int main()
{
b.a=3;
printf("%d\n", b.a);
return 0;
}
The file scope of structure tag B starts from its first definition/declaration struct B{int a;};.
How can struct B b; refer to B before B's scope without error?
Is struct B; a structure type declaration, or a structure type definition? Why does it not conflict with the other definition struct B{int a;}; in the same file scope?
struct B; is a structure declaration. There can be any number of declarations of the same object. For the kinds of objects that have multiple possible declarations, the declarations have to be compatible — for example you can have multiple prototypes for the same function, but they need to use the same argument and return types. For a structure, there's only one way to declare it without defining it, and it just says “there's a structure called B”. So it's ok to repeat struct B; as many times as you want.
struct B{int a;}; is a structure definition. There can only be one definition of a given object. Certain uses of an object require a prior definition, others only require a prior declaration. For example, you can define a variable whose type is a pointer to an undefined structure:
struct S;
struct S *p = NULL;
But you can't define a variable whose type is an undefined structure:
struct S;
struct S s = {0};
The reason for this difference is that a structure that hasn't been defined yet is an incomplete type — a type for which the compiler doesn't have a size. This isn't a problem to define a pointer, but it is a problem to define an object of the incomplete type: the compiler wouldn't know how much memory is required.
At this point, you may wonder why struct B b; is OK. After all, struct B hasn't even been declared, let alone defined.
The first part of why it's ok is that struct B b; declares the structure B in passing. So by the time struct B is needed to do something with b, the structure has just been declared.
The second part of why it's ok is that struct B b; is not exactly a definition. If it was a definition, then the compiler would need to know how much space to reserve, and an incomplete type would not be ok. This is what would happen if the variable was defined in a function:
void f(void) {
struct B b; // error: storage size of ‘b’ isn’t known
}
But when struct B b; is at the top level of a file, it's a tentative definition. A tentative definition is a declaration; for this, the structure doesn't need to have been defined. When the compiler gets to the end of the file, any tentative definition that hasn't had a proper definition, and for which a definition is needed, becomes a definition. At this point, the structure needs to have been defined. In your example program, b has a tentative definition, and that definition becomes a proper definition at the end of the file.
It's ok to not define the structure if the variable is unused, because it's ok to declare a variable with an incomplete type if the variable is not used.
struct B b;
// end of file
But if the variable is used in a way that requires a complete type, then the structure must have been defined at that point.
struct B b;
void f(void) {
sizeof(b); // error: invalid application of ‘sizeof’ to incomplete type ‘struct B’
}
struct B{int a;}; // too late
Question: How can struct B b; refer to B before B's scope without error?
Answer: From http://c0x.coding-guidelines.com/6.7.2.3.html in section 1471,
"If a type specifier of the form struct-or-union identifier
occurs other than as part of one of the above forms, and no other declaration of the identifier as a tag is visible, then it declares an incomplete structure or union type, and declares the identifier as the tag of that type."
So, you can use the struct tag as forward declaration before the struct type definition.
Question: Is struct B; a structure type declaration, or a structure type definition? Why does it not conflict with the other definition struct B{int a;}; in the same file scope?
Answer: From the same above link in section 1472,
"If a type specifier of the form struct-or-union identifier or enum identifier occurs other than as part of one of the above forms, and a declaration of the identifier as a tag is visible, then it specifies the same type as that other declaration, and does not redeclare the tag."
struct B; is a structure type declaration, struct B{int a;}; is a structure type definition and that's how they do not conflict each other.
You may choose to use the typedef to get rid of the confusion and show more visibility into your structure declaration:
typedef struct B B;
struct B{
int a;
};
B b;
The C standard states (§6.2.5 p22):
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).
And it works fine as far as variable declarations are concerned:
int a[];
int a[2]; //OK
But when we add typedef before those declarations the compiler complains (I also changed the name):
typedef int t[];
typedef int t[2]; //redefinition with different type
It doesn't complain however when we are completing a typedef to incomplete structure instead:
typedef struct t t1;
typedef struct t { int m; } t1; //OK
Possible use case of an incomplete typedef of array could be something like this:
int main(int n, char **pp)
{
typedef int t1[][200];
typedef struct t { t1 *m; int m1; } t0;
typedef int t1[sizeof (t0)][200];
}
In the above example I would like to declare a pointer to array inside a structure with number of elements equal to the structure size. Yes I could use a structure instead of array but why should I when the above option is potentially available?
typedef int t[2]; is not allowed because of the constraint 6.7/3:
If an identifier has no linkage, there shall be no more than one declaration of the identifier (in a declarator or type specifier) with the same scope and in the same name space, except that:
a typedef name may be redefined to denote the same type as it currently does, provided that type is not a variably modified type;
However int[] and int[2] are not the same type, so this "except" doesn't apply, and so the code violates the constraint.
Regarding your first quote: Although 6.2.5/22 says that an incomplete type can be completed, it doesn't follow that any attempted completion is automatically legal. The attempted completion must also comply with all the other rules of the language, and in this case it does not comply with 6.7/3.
The int a[]; int a[2]; example is OK (under 6.7/3) because a has linkage; and in the typedef struct t t1; , struct t is still the same type before and after its completion.
From 6.2.5p1, we can see a definition of the terms complete and incomplete:
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).
Thus, when we talk about a type being incomplete, we're really talking about the size of objects of that type being indeterminate. We can't talk about "incomplete types" without declaring an object of that type.
In your first example, the size of a is determinate as you've completed the definition for the object using the second declaration.
In your second example, no declaration for an object is made. Once the declaration is made, e.g. t x = { 1, 2 };, it becomes clear that the type isn't incomplete.
In your third example, you're not actually completing the type alias; you're completing the struct definition. You might as well have written:
typedef struct t t1;
struct t { int m; };
We can see further support for the redefinition of struct tags, and the exclusion of the VLA redefinition in 6.7p3:
If an identifier has no linkage, there shall be no more than one declaration of the identifier (in a declarator or type specifier) with the same scope and in the same name space, except that:
a typedef name may be redefined to denote the same type as it currently does, provided that type is not a variably modified type;
tags may be redeclared as specified in 6.7.2.3.
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.
Can you give chapter and verse from one of the three C standards (preferably C99 or C11) which indicates whether the following header file has one or two struct uperms_entry types in it?
#ifndef UPERMS_CACHE_INCLUDE
#define UPERMS_CACHE_INCLUDE
typedef struct mutex MT_MUTEX;
typedef struct uperms_cache
{
MT_MUTEX *cache_lock;
int processing;
struct uperms_entry *uperms_list; // No prior struct uperms_entry
} uperms_cache_t;
typedef struct uperms_entry // Does this define a different struct uperms_entry?
{
char username[32];
int perms;
struct uperms_entry *next;
} uperms_entry_t;
#endif /* UPERMS_CACHE_INCLUDE */
Adjunct questions:
If there are two types, is there any way to get GCC to report the issue?
If there are two types, does it ever matter in practice?
(I think the answers are 'yes — strictly there are two types', and then (1) No and (2) No.)
Context: internal code review — I'd like the order of the structures reversed, but I'm not sure whether I'm being completely overly pedantic.
Update:
Clearly, the answer to the initial question is 'there is one struct uperms_entry' and therefore the questions numbered 1 and 2 are moot. I'm glad I checked before throwing a hissy fit in a code review.
Background thinking
This section was added long after the primary question was resolved.
Here are some extensive but relevant quotes from ISO/IEC 9899:2011:
§6.2.7 Compatible type and composite type
¶1 Two types have compatible type if their types are the same.
Additional rules for determining whether two types are compatible are
described in 6.7.2 for type specifiers, in 6.7.3 for type qualifiers,
and in 6.7.6 for declarators.55) Moreover, two structure,
union, or enumerated types declared in separate translation units are
compatible if their tags and members satisfy the following requirements:
If one is declared with a tag, the other shall be declared with the same
tag. If both are completed anywhere within their respective translation
units, then the following additional requirements apply: there shall be
a one-to-one correspondence between their members such that each pair of
corresponding members are declared with compatible types; if one member
of the pair is declared with an alignment specifier, the other is
declared with an equivalent alignment specifier; and if one member of
the pair is declared with a name, the other is declared with the same
name. For two structures, corresponding members shall be declared in
the same order. For two structures or unions, corresponding bit-fields
shall have the same widths. For two enumerations, corresponding members
shall have the same values.
55) Two types need not be identical to be compatible.
§6.7.2.1 Structure and union specifiers
¶8 The presence of a struct-declaration-list in a
struct-or-union-specifier declares a new type, within a translation
unit. The struct-declaration-list is a sequence of declarations for the
members of the structure or union. If the struct-declaration-list does
not contain any named members, either directly or via an anonymous
structure or anonymous union, the behavior is undefined. The type is
incomplete until immediately after the } that terminates the list, and
complete thereafter.
§6.7.2.3 Tags
¶4 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 incomplete129) until
immediately after the closing brace of the list defining the content,
and complete thereafter.
¶5 Two declarations of structure, union, or enumerated types which are
in different scopes or use different tags declare distinct types. Each
declaration of a structure, union, or enumerated type which does not
include a tag declares a distinct type.
¶6 A type specifier of the form
struct-or-union identifieropt { struct-declaration-list }
or
enum identifieropt { enumerator-list }
or
enum identifieropt { enumerator-list , }
declares a structure, union, or enumerated type. The list defines the
structure content, union content, or enumeration content. If an
identifier is provided,130) the type specifier also declares
the identifier to be the tag of that type.
¶7 A declaration of the form
struct-or-union identifier ;
specifies a structure or union type and declares the identifier as a
tag of that type.131)
¶8 If a type specifier of the form
struct-or-union identifier
occurs other than as part of one of the above forms, and no other
declaration of the identifier as a tag is visible, then it declares an
incomplete structure or union type, and declares the identifier as the
tag of that type.131)
¶9 If a type specifier of the form
struct-or-union identifier
or
enum identifier
occurs other than as part of one of the above forms, and a declaration
of the identifier as a tag is visible, then it specifies the same type
as that other declaration, and does not redeclare the tag.
¶12 EXAMPLE 2 To illustrate the use of prior declaration of a tag to
specify a pair of mutually referential structures, the declarations
struct s1 { struct s2 *s2p; /* ... */ }; // D1
struct s2 { struct s1 *s1p; /* ... */ }; // D2
specify a pair of structures that contain pointers to each other.
Note, however, that if s2 were already declared as a tag in an
enclosing scope, the declaration D1 would refer to it, not to the tag
s2 declared in D2. To eliminate this context sensitivity, the
declaration
struct s2;
may be inserted ahead of D1. This declares a new tag s2 in the inner
scope; the declaration D2 then completes the specification of the new type.
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.
130) If there is no identifier, the type can, within the
translation unit, only be referred to by the declaration of which it is
a part. Of course, when the declaration is of a typedef name,
subsequent declarations can make use of that typedef name to declare
objects having the specified structure, union, or enumerated type.
131) A similar construction with enum does not exist.
§6.7.3 Type qualifiers
¶10 For two qualified types to be compatible, both shall have the
identically qualified version of a compatible type; the order of
type qualifiers within a list of specifiers or qualifiers does not
affect the specified type.
The discussion in §6.7.6 is related to pointer, arrays, and function
declarators and does not really affect structures or unions.
I was aware of Example 2 when I wrote the question. This is some
thinking out loud about some of what the information above means.
Consider this example, which compiles cleanly:
#include <stdio.h>
struct r1 { int x; };
struct r1;
struct r1 p0;
//struct r1 { int y; }; // Redefinition of struct r1
extern void z(void);
void z(void)
{
struct r1 p1 = { 23 };
struct r1;
//struct r1 p2; // Storage size of p2 is not known
struct r2 { struct r1 *rn; int y; };
struct r1 { struct r2 *rn; int z; };
struct r2 p = { 0, 1 };
struct r1 q = { &p, 2 };
p.rn = &q;
printf("p.y = %d, q.z = %d\n", p.y, q.z);
printf("p1.x = %d\n", p1.x);
}
The function illustrates when Example 2 applies, but is not sensible
code. The declaration of p1 in the function is would be a structure
of the same type as the global variable p0. Even though its type name
is struct r1, it is of a different (and incompatible) type from the
type of the local variable p.
The redefinition of struct r1 at the global level is not allowed,
regardless of whether the element is named x or y. The prior
struct r1; is a no-op in this context.
One interesting issue is 'can function z pass p or q to any other
function (call it a)? The answer is a qualified 'yes', and some of
the constraints are interesting. (It would also be appalling coding
style to try it, verging on the insane.) The function must exist in a
separate translation unit (TU). The function declaration must be inside
function z (because if it is outside the function, its prototype must
refer to the struct r1 defined outside the function, not the struct
r1 defined inside.
In the other TU, a degree of sanity must prevail: the function a must
have the compatible structure types struct r1 and struct r2 visible
in its global scope.
Here's another example, but this one does not compile:
#include <stdio.h>
struct r1;
extern void z(struct r1 *r1p);
extern void y(struct r1 *r1p);
void y(struct r1 *r1p)
{
struct r2 { struct r1 *rn; int y; };
struct r1 { struct r2 *rn; int z; };
struct r2 p = { r1p, 1 };
struct r1 q = { &p, 2 };
p.rn = &q;
printf("p.y = %d, q.z = %d\n", p.y, q.z);
}
void z(struct r1 *r1p)
{
struct r1
struct r2 { struct r1 *rn; int y; };
struct r1 { struct r2 *rn; int z; };
struct r2 p = { r1p, 1 };
struct r1 q = { &p, 2 };
p.rn = &q;
printf("p.y = %d, q.z = %d\n", p.y, q.z);
}
The warnings from GCC 4.7.1 on Mac OS X 10.7.4 are:
structs3.c: In function 'y':
structs3.c:13:10: warning: assignment from incompatible pointer type [enabled by default]
structs3.c: In function 'z':
structs3.c:22:12: warning: initialization from incompatible pointer type [enabled by default]
structs3.c:22:12: warning: (near initialization for 'p.rn') [enabled by default]
Lines 13 is the assignment p.rn = &q; in function y and line 23 is
the attempt to define and initialize struct r2 p in function z.
This demonstrates that within the functions, the rn element of struct
r2 is a pointer to the incomplete type struct r1 declared at the
global scope. Adding a struct r1; as the first line of code inside
the function would allow the code to compile, but the initialization
referencing r1p->rn is derefencing a pointer to an incomplete type
again (the incomplete type is the struct r1 declared at the global
scope).
The function declarations and the preceding struct r1; line could
appear in a header as an opaque type. The list of supporting functions
is incomplete; there'd need to be a way to get a pointer to an
initialized struct r1 to pass into the functions, but that's a detail.
To make the code work in this second TU, the types for struct r1 must
be complete in the global scope before the functions are defined, and
because of the recursive references, `struct r21 must also be complete.
#include <stdio.h>
/* Logically in a 3-line header file */
struct r1;
extern void z(struct r1 *r1p);
extern void y(struct r1 *r1p);
/* Details private to this TU */
struct r2 { struct r1 *rn; int y; };
struct r1 { struct r2 *rn; int z; };
void y(struct r1 *r1p)
{
struct r2 p = { r1p, 1 };
struct r1 q = { r1p->rn, 2 };
p.rn = &q;
printf("p.y = %d, q.z = %d\n", p.y, q.z);
}
void z(struct r1 *r1p)
{
struct r2 p = { r1p, 1 };
struct r1 q = { r1p->rn, 2 };
p.rn = &q;
printf("p.y = %d, q.z = %d\n", p.y, q.z);
}
This process of defining the structures in the implementation file while
leaving the type incomplete in the public header file can be repeated in
multiple implementation files if necessary, though if more than one TU
uses the complete structure definition, it would be better to place the
definitions in a private header file shared only between the files that
implement the structures. I note that it does not matter whether the
private header precedes or follows the public header.
Maybe this was all obvious to you already. I'd not needed to think it
through in this level of detail before.
In C1, they refer to the same type. C99 §6.2.1 defines the scopes that exist:
2 For each different entity that an identifier designates, the
identifier is visible (i.e., can be used) only within a region of
program text called its scope. Different entities designated by the
same identifier either have different scopes, or are in different name
spaces. There are four kinds of scopes: function, file, block, and
function prototype. (A function prototype is a declaration of a
function that declares the types of its parameters.)
Function scope only applies to labels (as explicitly stated later in the same section). Block scope applies to identifiers declared in blocks - blocks are created by compound-statements, iteration-statements and selection-statements (and not by struct declarations or compound initialisers). Function prototype scope applies to identifiers declared within a function prototype declaration.
None of these apply to your example - all of the mentions of struct uperms_entry in your example are at file scope.
C99 §6.7.2.3 says:
1 All declarations of structure, union, or enumerated types that have
the same scope and use the same tag declare the same type. The type is incomplete until the closing brace of the list defining the content, and complete thereafter.
This is pretty clear, and applies to your case.
Paragraph 8 of that section applies to the first mention of struct uperms_entry:
8 If a type specifier of the form struct-or-union identifier occurs
other than as part of one of the above forms, and no other declaration
of the identifier as a tag is visible, then it declares an incomplete
structure or union type, and declares the identifier as the tag of
that type.
So at that point it's declared as an incomplete type at file scope. Paragraph 6 applies to the second mention of struct uperms_entry:
6 A type specifier of the form struct-or-union
identifieropt { struct-declaration-list } or enum
identifier { enumerator-list } or enum identifier { enumerator-list
, } declares a structure, union, or enumerated type. The list defines
the structure content, union content, or enumeration content. If an
identifier is provided, the type specifier also declares the
identifier to be the tag of that type.
So after the } at the end of that typedef declaration, it's now a complete type.
The adjunct questions are moot.
1. I believe that this is not the case in C++, however.
Well, C99 6.2.5.22 says
... 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.
Which would mean they're the same type for your case.
As part of answering another question, I came across a piece of code like this, which gcc compiles without complaint.
typedef struct {
struct xyz *z;
} xyz;
int main (void) {
return 0;
}
This is the means I've always used to construct types that point to themselves (e.g., linked lists) but I've always thought you had to name the struct so you could use self-reference. In other words, you couldn't use xyz *z within the structure because the typedef is not yet complete at that point.
But this particular sample does not name the structure and it still compiles. I thought originally there was some black magic going on in the compiler that automatically translated the above code because the structure and typedef names were the same.
But this little beauty works as well:
typedef struct {
struct NOTHING_LIKE_xyz *z;
} xyz;
What am I missing here? This seems a clear violation since there is no struct NOTHING_LIKE_xyz type defined anywhere.
When I change it from a pointer to an actual type, I get the expected error:
typedef struct {
struct NOTHING_LIKE_xyz z;
} xyz;
qqq.c:2: error: field `z' has incomplete type
Also, when I remove the struct, I get an error (parse error before "NOTHING ...).
Is this allowed in ISO C?
Update: A struct NOSUCHTYPE *variable; also compiles so it's not just inside structures where it seems to be valid. I can't find anything in the c99 standard that allows this leniency for structure pointers.
As the warning says in the second case, struct NOTHING_LIKE_xyz is an incomplete type, like void or arrays of unknown size. An incomplete type can only appear in a struct as a type pointed to (C17 6.7.2.1:3), with an exception for arrays of unknown size that are allowed as the last member of a struct, making the struct itself an incomplete type in this case. The code that follows cannot dereference any pointer to an incomplete type (for good reason).
Incomplete types can offer some datatype encapsulation of sorts in C...
The corresponding paragraph in http://www.ibm.com/developerworks/library/pa-ctypes1/ seems like a good explanation.
The parts of the C99 standard you are after are 6.7.2.3, paragraph 7:
If a type specifier of the form
struct-or-union identifier occurs
other than as part of one of the above
forms, and no other declaration of the
identifier as a tag is visible, then
it declares an incomplete structure or
union type, and declares the
identifier as the tag of that type.
...and 6.2.5 paragraph 22:
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.
The 1st and 2nd cases are well-defined, because the size and alignment of a pointer is known. The C compiler only needs the size and alignment info to define a struct.
The 3rd case is invalid because the size of that actual struct is unknown.
But beware that for the 1st case to be logical, you need to give a name to the struct:
// vvv
typedef struct xyz {
struct xyz *z;
} xyz;
otherwise the outer struct and the *z will be considered two different structs.
The 2nd case has a popular use case known as "opaque pointer" (pimpl). For example, you could define a wrapper struct as
typedef struct {
struct X_impl* impl;
} X;
// usually just: typedef struct X_impl* X;
int baz(X x);
in the header, and then in one of the .c,
#include "header.h"
struct X_impl {
int foo;
int bar[123];
...
};
int baz(X x) {
return x.impl->foo;
}
the advantage is out of that .c, you cannot mess with the internals of the object. It is a kind of encapsulation.
You do have to name it. In this:
typedef struct {
struct xyz *z;
} xyz;
will not be able to point to itself as z refers to some complete other type, not to the unnamed struct you just defined. Try this:
int main()
{
xyz me1;
xyz me2;
me1.z = &me2; // this will not compile
}
You'll get an error about incompatible types.
Well... All I can say is that your previous assumption was incorrect. Every time you use a struct X construct (by itself, or as a part of larger declaration), it is interpreted as a declaration of a struct type with a struct tag X. It could be a re-declaration of a previously declared struct type. Or, it can be a very first declaration of a new struct type. The new tag is declared in scope in which it appears. In your specific example it happens to be a file scope (since C language has no "class scope", as it would be in C++).
The more interesting example of this behavior is when the declaration appears in function prototype:
void foo(struct X *p); // assuming `struct X` has not been declared before
In this case the new struct X declaration has function-prototype scope, which ends at the end of the prototype. If you declare a file-scope struct X later
struct X;
and try to pass a pointer of struct X type to the above function, the compiler will give you a diagnostics about non-matching pointer type
struct X *p = 0;
foo(p); // different pointer types for argument and parameter
This also immediately means that in the following declarations
void foo(struct X *p);
void bar(struct X *p);
void baz(struct X *p);
each struct X declaration is a declaration of a different type, each local to its own function prototype scope.
But if you pre-declare struct X as in
struct X;
void foo(struct X *p);
void bar(struct X *p);
void baz(struct X *p);
all struct X references in all function prototype will refer to the same previosly declared struct X type.
I was wondering about this too. Turns out that the struct NOTHING_LIKE_xyz * z is forward declaring struct NOTHING_LIKE_xyz. As a convoluted example,
typedef struct {
struct foo * bar;
int j;
} foo;
struct foo {
int i;
};
void foobar(foo * f)
{
f->bar->i;
f->bar->j;
}
Here f->bar refers to the type struct foo, not typedef struct { ... } foo. The first line will compile fine, but the second will give an error. Not much use for a linked list implementation then.
When a variable or field of a structure type is declared, the compiler has to allocate enough bytes to hold that structure. Since the structure may require one byte, or it may require thousands, there's no way for the compiler to know how much space it needs to allocate. Some languages use multi-pass compilers which would be able find out the size of the structure on one pass and allocate the space for it on a later pass; since C was designed to allow for single-pass compilation, however, that isn't possible. Thus, C forbids the declaration of variables or fields of incomplete structure types.
On the other hand, when a variable or field of a pointer-to-structure type is declared, the compiler has to allocate enough bytes to hold a pointer to the structure. Regardless of whether the structure takes one byte or a million, the pointer will always require the same amount of space. Effectively, the compiler can tread the pointer to the incomplete type as a void* until it gets more information about its type, and then treat it as a pointer to the appropriate type once it finds out more about it. The incomplete-type pointer isn't quite analogous to void*, in that one can do things with void* that one can't do with incomplete types (e.g. if p1 is a pointer to struct s1, and p2 is a pointer to struct s2, one cannot assign p1 to p2) but one can't do anything with a pointer to an incomplete type that one could not do to void*. Basically, from the compiler's perspective, a pointer to an incomplete type is a pointer-sized blob of bytes. It can be copied to or from other similar pointer-sized blobs of bytes, but that's it. the compiler can generate code to do that without having to know what anything else is going to do with the pointer-sized blobs of bytes.