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;
Related
The following is a legal fragment in C:
/* Example 1. */
struct B *p; /* p: pointer to incomplete struct type B */
/* This declaration completes the struct type B. */
struct B {
int foo;
};
As long as no pointer operations are performed on p (e.g. p++) until complete type information for struct type B is provided, the fragment is legal C.
On the other hand, the next fragment is illegal in C:
/* Example 2. */
T_t *p; /* p: pointer to undeclared type T_t. */
typedef int T_t;
Question: What is the reason that it is legal in C to declare a pointer to an incomplete struct type and provide the complete struct type information later (Example 1), whereas it is illegal to declare a pointer to an undeclared type and declare the type later (Example 2)?
Because of the struct keyword, it is known what kind of entity struct B refers to, even before struct B is declared. It is a type --- a struct type, to be more precise. It is an incomplete type, because the declaration of struct B has not been seen yet. But for some uses, such as declaring a pointer, it is sufficient.
On the other hand it is not known what T_t is. Is it a type? Is it a variable? Is it a function? Is it an enumerator? If it is a type, we are OK. If it is not, this declaration either makes no sense, or worse, has more than one meaning depending on what T_t is.
The C language is defined in such a way that the compiler does not need to look ahead much. It reads from top to bottom and decides on the spot. Can T_t *p; be interpreted unambiguously based on what is already seen? If not, then it is invalid.
Types with "tags" (struct, union, enum) have special rules (c17 6.7.2.3):
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 until immediately after the closing brace of the list defining the content, and complete thereafter.
This allows for forward declaration of an incomplete type which will later be completed. In case of structs there are some useful applications for this feature: it allows self-referencing structs (like linked list nodes) and it allows private encapsulation in the form of "opaque types", where the struct definition is hidden outside the translation unit.
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};
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
What are declarator specifiers and type specifiers in C language?
Can user define or create declarator specifiers or type specifiers?
I am reading GCC source code, if you can give me some advice, I will be very thankful!
Below is from GCC/c-tree.h
/* A kind of type specifier. Note that this information is currently
only used to distinguish tag definitions, tag references and typeof
uses. */
enum c_typespec_kind {
/* No typespec. This appears only in struct c_declspec. */
ctsk_none,
/* A reserved keyword type specifier. */
ctsk_resword,
/* A reference to a tag, previously declared, such as "struct foo".
This includes where the previous declaration was as a different
kind of tag, in which case this is only valid if shadowing that
tag in an inner scope. */
ctsk_tagref,
/* A reference to a tag, not previously declared in a visible
scope. */
ctsk_tagfirstref,
/* A definition of a tag such as "struct foo { int a; }". */
ctsk_tagdef,
/* A typedef name. */
ctsk_typedef,
/* An ObjC-specific kind of type specifier. */
ctsk_objc,
/* A typeof specifier, or _Atomic ( type-name ). */
ctsk_typeof
};
Declaration in C
In C the syntax for a declaration is of the form:
declaration-specifiers declarator
declarator are variables or functions or pointers and basically correspond to the name of the object declared.
specifiers can be type specifiers like int, unsigned, etc. or storage class specifier like typedef, extern, static or type qualifiers like const, volatile, etc.
For example in the following declaration:
typedef long double DBL;
We have introduced a new type name DBL which is an alias for long double and we have:
typedef: storage class specifier
long double: type specifier
DBL: declarator
When you use typedef you are basically aliasing a type specifier with a new name. If you typedef a struct like in the following:
typedef struct {
int a;
int b;
} mystruct;
Then you can specifiy the type of a variable to be mystruct, like in the following declaration:
mystruct c;
Related posts:
What are declarations and declarators and how are their types interpreted by the standard? and
How do I use typedef and typedef enum in C? and
Declaration specifiers and declarators
Declarators are the components of a declaration that specify names of objects or functions. Declarators also specify whether or not the named object is an object, pointer, reference or array. While declarators do not specify the base type, they do modify the type information in the basic type to specify derived types such as pointers, references, and arrays. Applied to functions, the declarator works with the type specifier to fully specify the return type of a function to be an object, pointer, or reference.Reference link Here.Which is provide more information about Declarators.
Declarators for Pointers
int *i; // declarator is *i
int **i; // declarator is **i;
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.