What are declarator specifiers in C language? [closed] - c

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;

Related

C pointer to incomplete struct type and later struct type completion VS. pointer to undeclared type T_t and later type T_t declaration

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.

an error about C struct array in formal parameter

I have got the following code:
struct student_info;
void paiming1(struct student_info student[]);
struct student_info
{
int num;
char name[6];
};
The IDE gives an error
error: array type has incomplete element type ‘struct student_info’
void paiming1(struct student_info student[]);
But if I use void paiming1(struct student_info *student); it works OK. Why is that? I am using GCC.
С language unconditionally requires array element type in all array declarations to be complete. Period.
6.7.6.2 Array declarators
Constraints
1 [...] The element type shall not be an incomplete or function
type. [...]
No exception is made for array declarations used in function parameter lists. This is different from C++ - the latter drops this completeness requirement for function parameter lists
struct S;
void foo(struct S[]); // OK in C++, invalid in C
Considering that in parameter list declaration type T [] is later adjusted to type T * anyway, this requirement might appear to be excessive. (And this is why C++ relaxed it.) Nevertheless, this restriction is present in C language. This is just one of the quirks of C language.
As you already know, you can explicitly switch to the equivalent
void paiming1(struct student_info *student);
form to work around the issue.
Careful reading of the standard makes it clear that in C99 and C11 the declaration is supposed to be a constraint violation. C11 6.7.2.6 Array declarations p1
In addition to optional type qualifiers and the keyword static, the [ and ] may delimit an expression or *. If they delimit an expression (which specifies the size of an array), the expression shall have an integer type. If the expression is a constant expression, it shall have a value greater than zero. The element type shall not be an incomplete or function type. The optional type qualifiers and the keyword static shall appear only in a declaration of a function parameter with an array type, and then only in the outermost array type derivation.
Since this contains references to the * that is valid only in function declarations that are not definitions, and nowhere else, the constraints as whole needs to be taken as applying to parameters.
For C90 the case is more complicated. This is actually discussed in C90 Defect Report 47 from 10 December, 1992.
2 of the 6 declarations given there are
/* 1. */ struct S;
/* 3. */ struct S *g(struct S a[]) { return a; }
and the defect report asks if these are strictly-conforming. It must be noted that unlike the question, these are prototypes that are part of definition rather than just declaration.
Nevertheless, the standard committee responds by saying that
The struct S is an incomplete type (subclause 6.5.2.3, page 62, lines 25-28). Also, an array of unknown size is an incomplete type (subclause 6.5.4.2, page 67, lines 9-10). Therefore, arrays of either of the above are not strictly conforming (subclause 6.1.2.5, page 23, lines 23-24). This makes declarations 3, 4, and 6 not strictly conforming. (But an implementation could get it right.)
As an aside, array parameters are adjusted to pointer type (subclause 6.7.1, page 82, lines 23-24). However, there is nothing to suggest that a not-strictly-conforming array type can magically be transformed into a strictly conforming pointer parameter via this rule.
The types in question can be interpreted two different ways. (Array to pointer conversion can happen as soon as possible or as late as possible.) Hence a program that uses such a form has undefined behavior.
(emphasis mine)
Since this has not been clarified in writing since 1992, we must agree that the behaviour is undefined and therefore the C standard imposes no requirements, and a compiler that successfully compiles this this can still conform to C90.
The committee also states that there is no constraint violation in C90, therefore a C90 conforming compiler need not output any diagnostics.
I've edited the answer; I previously claimed that this would apply to C99 and C11 alike, but the text was changed in C99 as above, therefore this is a constraint violation in C99, C11.
Compiler doesn't know anything about size of struct student_info until it is declared. This should work:
struct student_info
{
int num; //学号
char name[6]; //姓名
char sex[5]; //性别
char adress[20]; //家庭住址
char tel[11]; //电话
int chinese,math,english,huping,pingde,jiaoping,paiming1,paiming2;
double ave,zhongping;
};
void paiming1(struct student_info student[]);
void paiming2(struct student_info student[]);
When you declare it as a pointer using *, compiler knows the size of the argument (its an address).

Structure Confusion

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.

Is it a definition or a declaration? [duplicate]

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;

Which part of the C standard allows this code to compile?

I was bug-fixing some code and the compiler warned (legitimately) that the function dynscat() was not declared — someone else's idea of an acceptable coding standard — so I tracked down where the function is defined (easy enough) and which header declared it (none; Grrr!). But I was expecting to find the details of the structure definition were necessary for the extern declaration of qqparse_val:
extern struct t_dynstr qqparse_val;
extern void dynscat(struct t_dynstr *s, char *p);
extern void qqcat(char *s);
void qqcat(char *s)
{
dynscat(&qqparse_val, s);
if (*s == ',')
dynscat(&qqparse_val, "$");
}
The qqcat() function in the original code was static; the extern declaration quells the compiler warning for this snippet of the code. The dynscat() function declaration was missing altogether; again, adding it quells a warning.
With the code fragment shown, it's clear that only the address of the variable is used, so it makes sense at one level that it does not matter that the details of the structure are not known. Were the variable extern struct t_dynstr *p_parseval;, you'd not be seeing this question; that would be 100% expected. If the code needed to access the internals of the structure, then the structure definition would be needed. But I'd always expected that if you declared that the variable was a structure (rather than a pointer to the structure), the compiler would want to know the size of the structure — but apparently not.
I've tried provoking GCC into complaining, but it doesn't, even GCC 4.7.1:
gcc-4.7.1 -c -Wall -Wextra -std=c89 -pedantic surprise.c
The code has been compiling on AIX, HP-UX, Solaris, Linux for a decade, so it isn't GCC-specific that it is accepted.
Question
Is this allowed by the C standard (primarily C99 or C11, but C89 will do too)? Which section? Or have I just hit on an odd-ball case that works on all the machines it's ported to but isn't formally sanctioned by the standard?
What you have is an incomplete type (ISO/IEC 9899:1999 and 2011 — all these references are the same in both — §6.2.5 ¶22):
A structure or union type of unknown content (as described in §6.7.2.3) is an incomplete
type.
An incomplete type can still be an lvalue:
§6.3.2.1 ¶1 (Lvalues, arrays, and function designators)
An lvalue is an expression with an object type or an incomplete type other than void; ...
So as a result it's just like any other unary & with an lvalue.
Looks like a case of taking the address of an object with incomplete type.
Using pointers to incomplete types is totally sane and you do it each time you use a pointer-to-void (but nobody ever told you :-)
Another case is if you declare something like
extern char a[];
It is not surprising that you can assign to elements of a, right? Still, it is an incomplete type and compilers will tell you as soon as you make such an identifier the operand of a sizeof.
your line
extern struct t_dynstr qqparse_val;
Is an external declaration of an object, and not a definition. As an external object it "has linkage" namely external linkage.
The standard says:
If an identifier for an object is declared with no linkage, the type for the object shall be complete by the end of its declarator, ...
this implies that if it has linkage the type may be incomplete. So there is no problem in doing &qqparse_val afterwards. What you wouldn't be able to do would be sizeof(qqparse_val) since the object type is incomplete.
A declaration is necessary to "refer" to something.
A definition is necessary to "use" something.
A declaration may provide some limited definition as in "int a[];"
What stumps me is:
int f(struct _s {int a; int b;} *sp)
{
sp->a = 1;
}
gcc warn the 'struct _s' is declared inside parameter list. And states "its scope is ONLY this definition or declaration,...". However it does not give an error on "sp->a" which isn't in the parameter list. When writing a 'C' parser I had to decide where the definition scope ended.
Focusing on the first line:
extern struct t_dynstr qqparse_val;
It can be divided into the separate steps of creating the type and the variable, resulting in this equivalent pair of lines:
struct t_dynstr; /* declaration of an incomplete (opaque) struct type */
extern struct t_dynstr qqparse_val; /* declaration of an object of that type */
The second line looks just like the original, but now it's referring to the type that already exists because of the first line.
The first line works because that's just how opaque structs are done.
The second line works because you don't need a complete type to do an extern declaration.
The combination (second line works without the first line) works because combining a type declaration with a variable declaration works in general. All of these are using the same principle:
struct { int x,y; } loc; /* define a nameless type and a variable of that type */
struct point { int x,y; } location; /* same but the type has a name */
union u { int i; float f; } u1, u2; /* one type named "union u", two variables */
It looks a little funny with the extern being followed immediately by a type declaration, like maybe you're trying to make the type itself "extern" which is nonsense. But that's not what it means. The extern applies to the qqparse_val in spite of their geographical separation.
Here's my thoughts relative to the standard (C11).
Section 6.5.3.2: Address and indirection operators
Constraints
Paragraph 1: The operand of the unary & operator shall be either a function designator, the result of a [] or unary * operator, or an lvalue that designates an object that is not a bit-field and is not declared with the register storage-class specifier.
Paragraph 2: The operand of the unary * operator shall have pointer type.
Here, we don't specify any requirement on the object, other than that it is an object (and not a bitfield or register).
On the other hand, let's look at sizeof.
6.5.3.4 The sizeof and _Alignof operators
Constraints
Paragraph 1: The sizeof operator shall not be applied to an expression that has function type or an incomplete type, to the parenthesized name of such a type, or to an expression that designates a bit-field member. The _Alignof operator shall not be applied to a function type or an incomplete type.
Here, the standard explicitly requires the object to not be an incomplete type.
Therefore, I think this is a case of what is not explicitly denied is allowed.

Resources