Its been a while that I am not in touch with the C language, so I was just going through some of the concepts but could not find any good source on structures.
Can anyone please explain
struct A
{
int a;
char b;
float c;
};
Is this the declaration or the definition of the structure A.
It declares a struct with the struct tag A and the specified members. It does neither define nor reserve any storage for an object.
From the C99 Standard, 6.7 Declarations:
Semantics
5 A declaration specifies the interpretation and attributes of a set of
identifiers. A definition of an identifier is a declaration for that
identifier that:
— for an object, causes storage to be reserved for
that object;
— for a function, includes the function body; (footnote 98)
— for an
enumeration constant or typedef name, is the (only) declaration of the
identifier.
For a definition, you would need to provide an object identifier before the final semicolon:
struct A
{
int a;
char b;
float c;
} mystruct;
To also initialize mystruct you would write
struct A
{
int a;
char b;
float c;
} mystruct = { 42, 'x', 3.14 };
It is a declaration.
struct A; is a forward declaration or incomplete declaration.
struct A
{
int a;
char b;
float c;
};
is complete struct declaration.
Example
Also check comp.lang.c FAQ list Question 11.5
After forward declaration of struct, you can use structure pointers but can not dereference the pointers or use sizeof operator or create instances of the struct.
After declaration, you can also use struct objects, apply the sizeof operator etc.
From 6.7.2.1 Structure and union specifiers from C11 specs
8 The type is incomplete until immediately after the } that terminates
the list, and complete thereafter.
And from 6.7.2.3 Tags
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)131A similar construction with enum does not exist
This should not be confused with extern struct A aa; v/s struct A aa ={/*Some values*/}; which are declaration and definitions of object aa.
Related
struct Figlio
{
char nome[256];
struct Genitore* padre;
struct Genitore* madre;
};
struct Genitore
{
char nome[256];
struct Figlio* progenie;
};
int main()
{
return 0;
}
I expected that the above code does not compile since struct Genitore is not declared before Figlio, so a forward declaration of Genitore (i.e., struct Genitore; on the top) was needed. Instead, in C, it compiles without any problem.
Instead, if I pass a not-yet declared struct pointer to a function, e.g.,
void f(struct st*);
struct st{};
it raises the following warning
Warning: ‘struct st’ declared inside parameter list will not be visible outside of this definition or declaration
So, I don't understand why these different behaviours and, especially, why forward declarations of struct Genitore; and struct st; respectively are not requested.
This is a matter of scope.
First, for the rule regarding a struct tag, section 6.2.1p7 of the C standard states:
Structure, union, and enumeration tags have scope that begins just after the appearance of
the tag in a type specifier that declares the tag. ...
Which is what allows the appearance of a struct tag to act as a declaration wherever it appears. This also allows a struct to contain a pointer to itself and have it refer to the same type.
Then the rules for the scope of identifiers is listed in section 6.2.1p4:
Every other identifier has scope determined by the placement of its
declaration (in a declarator or type specifier). If the declarator or
type specifier that declares the identifier appears outside of any
block or list of parameters, the identifier has file scope, which
terminates at the end of the translation unit. If the declarator or
type specifier that declares the identifier appears inside a block or
within the list of parameter declarations in a function definition,
the identifier has block scope, which terminates at the end of the
associated block. 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. If an identifier designates two different
entities in the same name space, the scopes might overlap. If so, the
scope of one entity (the inner scope) will end strictly before the
scope of the other entity (the outer scope). Within the inner scope,
the identifier designates the entity declared in the inner scope; the
entity declared in the outer scope is hidden (and not visible) within
the inner scope
Note in particular the two bolded passages. The implicit declaration of struct Genitore when declaring a pointer to that type as a member of struct Figlio has file scope, since it does not appear in a block statement and does not appear in a function declaration, and therefore is visible from that point down in the source file.
In contrast, the implicit declaration that appears in the function declaration is only in scope for the declaration itself. Such a type declaration is problematic because any potential struct pointer that you pass in will refer to a different type than the one implicitly declared in the function declaration.
In this declaration
struct Figlio
{
char nome[256];
struct Genitore* padre;
struct Genitore* madre;
};
you declared two pointers to the incomplete type struct Genitore.
A pointer type is a complete object type.
That is in these declarations you declared the incomplete type struct Genitore and objects of the pointer type struct Genitore *.
The declaration of the structure type struct Genitore is visible in the scope where the structure Figlio is declared (in a file scope or a block scope)
Another example of introducing an incomplete structure type is a declaration it in a typedef declaration for example
typedef struct A A;.
You can define the structure somewhere below after the typedef declaration in the same scope.
Another example is declaring a structure incomplete type in the return type of a function declaration. For example
struct A f( void );
Again you will need to define the structure at least before the function definition or before a function call.
Here is a demonstration program.
#include <stdio.h>
struct A f( void );
struct A { int x; } f( void )
{
struct A a = { .x = 10 };
return a;
};
int main( void )
{
struct A a = f();
printf( "a.x = %d\n", a.x );
}
The program output is
a.x = 10
On the other hand, if you will try to dereference a pointer to an incomplete type the compiler will issue an error.
In this declaration
void f(struct st*);
the type specifier struct st has the function prototype scope and is not visible outside the function parameter list.
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.
Is such heavy use of backreferencing a declaration from the initialization code covered by at least one of the standards (C99-current) or is it a gcc extension?
All the member initialization terms have in common that they either reference the type or a member/variable of that type from within the definition of the type.
#include <stddef.h>
#include <stdlib.h>
struct node{
int size;
int offset;
int *ptr;
struct node *this;
} s = {sizeof(s), offsetof(struct node, offset), &s.offset, &s};
int main(void){
struct node *s = malloc(sizeof(*s));
free(s)
}
I googled around using the searchterms backreferencing declaration from definition, backreferencing declaration from initialization, c initialization struct referencing declaration etc, but all just provide me the differences between declaration and definition. However, i would like to know what is allowed by the standard when i reference the type or a member/variable of that type from within the definition.
In general, you can't refer to struct members from inside the declaration list. For example, this code has undefined behavior:
typedef struct { int x; int y; } foo_t;
foo_t foo = { .x=5, .y=x }; // BAD, the order of initialization between x and y is not defined
For your specific case though, this does not apply. First of all, the struct definition ends at the } - from there on it is a complete type, something that has a full definition visible in the current file (pedantically: in the current translation unit).
You then have these cases of initializers:
sizeof(s). Since you have a complete type (not a forward-declared struct or a variable-length array etc), using sizeof is fine. It yields an integer constant expression (C17 6.6/6) and is calculated at compile-time.
offsetof same deal as with sizeof.
&s.offset and &s. These are address constants, one type of constant expressions (C17 6.6/7). These are allowed inside an initializer list too and also calculated at compile-time.
So all of your initializers are constant expressions - meaning the initializer list is valid. Even if you were to declare this struct with static storage duration.
There is nothing strange here. When we come to the =, the initialization starts and the declaration is completely done. The sizeof operator requires a complete type, which your struct is. This would not work for instance:
struct x;
int n = sizeof x;
Also, in your case you not only have a complete type. You have also declared an object s. And because of that, both &s.offset and &s is completely valid.
There some cases where backreferencing does not work. Here is one:
int x[] = { sizeof x };
which yields this error:
error: invalid application of ‘sizeof’ to incomplete type ‘int[]’
2 | int x[] = {sizeof x};
I was looking into the C11 draft and it says
An unnamed member of structure type with no tag is called an anonymous structure; an unnamed member of union type with no tag is called an anonymous union. The members of an anonymous structure or union are considered to be members of the containing structure or union.
So I constructed the following testcase
// struct type with no tag
typedef struct {
unsigned char a;
unsigned char b;
// ... Some other members ...
unsigned char w;
} AToW;
union
{
AToW; // <- unnamed member
unsigned char bytes[sizeof(AToW)];
} myUnion;
Clang and GCC both complain about the unnamed member, saying that the declaration has no effect. Did I do something wrong, or do they simply not support that feature yet?
No, that's not an unnamed member.
An example is:
struct outer {
int a;
struct {
int b;
int c;
};
int d;
};
The inner structure containing members b and c is an unnamed member of struct outer. The members of this unnamed member, b and c, are considered to be members of the containing structure.
This is probably more useful with a contained union rather than a contained structure. In particular, it can be used to define something similar to a Pascal or Ada variant record:
enum variant_type { t_int, t_double, t_pointer, t_pair };
struct variant {
enum variant_type type;
union {
int i;
double d;
void *p;
struct {
int x;
int y;
};
};
};
This lets you refer to i, d, and p directly as members of a struct variant object rather than creating an artificial name for the variant portion. If some variants require more than one member, you can nest anonymous structures within the anonymous union.
(It differs from Pascal and Ada in that there's no mechanism to enforce which variant is active given the value of the type member; that's C for you.)
In your example, AToW is a typedef for a struct type that you defined previously. You're not permitted to have a bare
AToW;
in the middle of a struct definition, any more than you can have a bare
int;
C11 added the ability to define a nested anonymous struct within another struct, but only by defining a new anonymous struct type at that point. You can't have an anonymous struct member of a previously defined type. The language could have been defined to permit it, and the semantics would (I think) be reasonably straightforward -- but there wasn't much point in defining two different ways to do the same thing. (For "struct" in the above, read "struct or union".)
Quoting the N1570 draft (which is very close to the released 2011 ISO C standard), section 6.7.2.1 paragraph 13:
An unnamed member whose type specifier is a structure specifier with
no tag is called an anonymous structure; an unnamed member whose type
specifier is a union specifier with no tag is called an anonymous
union. 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.
A structure specifier consists of the keyword struct, followed by an optional identifier (the tag, omitted in this case), followed by a sequence of declarations enclosed in { and }. In your case, AToW is a type name, not a structure specifier, so it can't be used to define an anonymous structure.
This question already has answers here:
What is the difference between a definition and a declaration?
(27 answers)
Closed 8 years ago.
struct foo {
char name[10];
char title[10];
int salary;
};
In the above code is it a structure definition or structure declaration ?
I'm learning structures in C, some books says that it is a declaration, some says it is a definition. So what exactly it is ?
From what I understand a declaration specifies the compiler what the type and name of a variable is, where as a definition causes memory space allocated for the variable.
It's a declaration. It declares the type struct foo.
(C99, 6.7p5) "A declaration specifies the interpretation and attributes of a set of identifiers. A definition
of an identifier is a declaration for that identifier that:
— for an object, causes storage to be reserved for that object;
— for a function, includes the function body;101)
— for an enumeration constant or typedef name, is the (only) declaration of the
identifier."
Your understanding is correct. Your code example is a declaration of a type. In 'C' you can declare a type and immediately use it to define a variable.
So your example is a pure declaration.
And here is an example of declaration+variable definition:
struct foo {
char name[10];
char title[10];
int salary;
} var;
What is the definition of Incomplete Type and Object Type in C? Also, could you provide some examples of each?
ANSI C99 mentions both type categories in various places, though I've found it difficult to understand what each of them means exactly (there is no paragraph/sentence explicitly defining what they are).
Let's go to the online C standard (draft n1256):
6.2.5 Types
1 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 fully describe objects), function types (types that describe functions), and incomplete types (types that describe objects but lack information needed to determine their sizes).
Examples of incomplete types:
struct f; // introduces struct f tag, but no struct definition
int a[]; // introduces a as an array but with no defined size
You cannot create instances of incomplete types, but you can create pointers and typedef names from incomplete types:
struct f *foo;
typedef struct f Ftype;
To turn the incomplete struct type into an object type, we have to define the struct:
struct f
{
int x;
char *y;
};
The types I know of are:
Incomplete type
object type
function type
Here's an example (also on codepad: http://codepad.org/bzovTRmz )
#include <stddef.h>
int main(void) {
int i;
struct incomplete *p1;
int *p2;
int (*p3)(void);
p1 = NULL; /* p1 is a pointer to a incomplete type */
p2 = &i; /* p2 is a pointer to an object */
p3 = main; /* p3 is a pointer to a function */
return 0;
}
The struct incomplete can be defined (with a definite size) in another translation unit. This translation unit only needs the pointer though