Jones D.M.The new C standard (C90 and C++).An economic and cultural commentary.2005
.pdf1354 6.7.1 Storage-class specifiers
3.1p2
declaration specifiers
C++
A declaration is a definition unless . . . , or it is a typedef declaration (7.1.3), . . .
A typedef name is not considered to be a definition in C ++. However, this difference does not cause any C compatibility consequences. Enumerations constants are not explicitly excluded in the unless list. They are thus definitions.
The declaration specifiers consist of a sequence of specifiers that indicate the linkage, storage duration, and 1347 part of the type of the entities that the declarators denote.
declarator list of
C++
The C++ Standard does not make this observation.
The init-declarator-list is a comma-separated sequence of declarators, each of which may have additional 1348 type information, or an initializer, or both.
C++
object
type complete by end
The C++ Standard does not make this observation.
If an identifier for an object is declared with no linkage, the type for the object shall be complete by the end 1351 of its declarator, or by the end of its init-declarator if it has an initializer;
C++
3.1p6
A program is ill-formed if the definition of any object gives the object an incomplete type (3.9).
The C++ wording covers all of the cases covered by the C specification above.
A violation of this requirement must be diagnosed by a conforming C++ translator. There is no such requirement on a C translator. However, it is very unlikely that a C implementation will not issue a diagnostic in this case (perhaps because of some extension being available).
in the case of function arguments (including in prototypes), it is the adjusted type (see 6.7.5.3) that is required 1352 to be complete.
C90
This wording was added to the C99 Standard to clarify possible ambiguities in the order in which requirements, in the standard, were performed on parameters that were part of a function declaration; for instance, int f(int a[]);.
C++
The nearest the C++ Standard comes to specifying such a rule is:
5.2.2p4
When a function is called, the parameters that have object type shall have completely-defined object type. [Note: this still allows a parameter to be a pointer or reference to an incomplete class type. However, it prevents a passed-by-value parameter to have an incomplete class type. ]
6.7.1 Storage-class specifiers
v 1.0b |
September 2, 2005 |
6.7.1 Storage-class specifiers 1359
1354
storage-class-specifier: typedef
extern static auto register
C++
The C++ Standard classifies typedef (7.1p1) as a decl-specifier, not a storage-class-specifier
(which also includes mutable, a C++ specific keyword).
Constraints
1355 At most, one storage-class specifier may be given in the declaration specifiers in a declaration. 100)
C++
storageclass specifier syntax
While the C++ Standard (7.1.1p1) contains the same requirement, it does not include typedef in the list of storage-class-specifiers. There is no wording in the C++ limiting the number of instances of the typedef decl-specifier in a declaration.
Source developed using a C++ translator may contain more than one occurrence of the typedef decl-specifier in a declaration.
Semantics
1356 The typedef specifier is called a “storage-class specifier” for syntactic convenience only;
C++
It is called a decl-specifier in the C++ Standard (7.1p1).
1359 A declaration of an identifier for an object with storage-class specifier register suggests that access to the object be as fast as possible.
C++
A register specifier has the same semantics as an auto specifier together with a hint to the implementation that the object so declared will be heavily used.
Translator implementors are likely to assume that the reason a developer provides this hint is that they are expecting the translator to make use of it to improve the performance of the generated machine code. The
register storage-class
7.1.1p3
September 2, 2005 |
v 1.0b |
1368 |
6.7.2 Type specifiers |
|
|||
|
|
C++ hint does not specify implementation details. The differing interpretations given, by the two standards, |
|
||
|
|
for hints provides to translators is not likely to be significant. The majority of modern translators ignore the |
|
||
|
|
hint and do what they think is best. |
|
||
|
|
|
|
|
|
register |
|
The extent to which such suggestions are effective is implementation-defined. 101) |
1360 |
||
extent effective |
|
||||
|
|
C++ |
|
||
|
|
The C++ Standard gives no status to a translators implementation of this hint (suggestion). A C++ translator |
|
||
|
|
is not required to document its handling of the register storage-class specifier and often a developer is no |
|
||
|
|
less wiser than if it is documented. |
|
||
|
|
|
|
1364 |
|
|
|
However, whether or not addressable storage is actually used, the address of any part of an object declared |
|||
|
with storage-class specifier register cannot be computed, either explicitly (by use of the unary & operator |
|
|||
|
|
as discussed in 6.5.3.2) or implicitly (by converting an array name to a pointer as discussed in 6.3.2.1). |
|
unary & 1078 operand
constraints
C++
This requirement does not apply in C++.
Thus, the only operator that can be applied to an array declared with storage-class specifier register is 1365 sizeof.
unary & 1078 operand
constraints
C++
This observation is not true in C++.
If an aggregate or union object is declared with a storage-class specifier other than typedef, the properties 1366 resulting from the storage-class specifier, except with respect to linkage, also apply to the members of the
object, and so on recursively for any aggregate or union member objects.
C90
This wording did not appear in the C90 Standard and was added by the response to DR #017q6.
C++
The C++ Standard does not explicitly specify the behavior in this case.
6.7.2 Type specifiers
type specifier |
|
|
|
|
|
syntax |
1368 |
|
|
||
|
type-specifier: |
|
|
void |
|
|
char |
|
|
short |
|
|
int |
|
|
long |
|
|
float |
|
|
double |
|
|
signed |
|
|
unsigned |
|
|
_Bool |
|
|
_Complex |
|
|
_Imaginary |
|
|
struct-or-union-specifier |
|
|
enum-specifier |
|
|
typedef-name |
v 1.0b |
September 2, 2005 |
6.7.2 Type specifiers 1372
C90
Support for the type-specifiers _Bool, _Complex, and _Imaginary is new in C99.
C++
The nonterminal for these terminals is called simple-type-specifier in C++ (7.1.5.2p1). The C++ Standard does contain a nonterminal called type-specifier. It is used in a higher-level production (7.1.5p1) that includes cv-qualifier.
The C++ Standard includes wchar_t and bool (the identifier bool is defined as a macro in the header stdbool.h in C) as type-specifiers (they are keywords in C++). The C++ Standard does not include _Bool, _Complex and _Imaginary, either as keywords or type specifiers.
Constraints
1369 At least one type specifier shall be given in the declaration specifiers in each declaration, and in the specifierqualifier list in each struct declaration and type name.
C90
This requirement is new in C99.
In C90 an omitted type-specifier implied the type specifier int. Translating a source file that contains such a declaration will cause a diagnostic to be issued and are no longer considered conforming programs.
declaration at least one type specifier
C++ |
|
|
|
|
7.1.5p2 |
|
At least one type-specifier that is not a cv-qualifier is required in a declaration unless it declares a |
|
|
constructor, destructor or conversion function.80) |
|
|
|
|
Although the terms used have different definitions in C/C ++, the result is the same.
1372
--~ void --~ char
--~ signed char --~ unsigned char
--~ short, signed short, short int, or signed short int --~ unsigned short, or unsigned short int
--~ int, signed, or signed int --~ unsigned, or unsigned int
--~ long, signed long, long int, or signed long int --~ unsigned long, or unsigned long int
--~ long long, signed long long, long long int, or signed long long int --~ unsigned long long, or unsigned long long int
--~ float --~ double
--~ long double --~ _Bool
--~ float _Complex --~ double _Complex
--~ long double _Complex --~float _Imaginary --~double _Imaginary --~long double _Imaginary
--~ struct or union specifier --~ enum specifier
--~ typedef name
type specifiers possible sets of
September 2, 2005 |
v 1.0b |
1378 6.7.2 Type specifiers
C90
Support for the following is new in C99:
— long long, signed long long, long long int, or signed long long int
—unsigned long long, or unsigned long long int
—_Bool
—float _Complex
—double _Complex
—long double _Complex
Support for the no type specifiers set, in the int, signed, signed int list has been removed in C99.
/* strictly conforming C90 */
2/* constraint violation C99 */
3 const y; |
/* strictly conforming C90 */ |
4/* constraint violation C99 */
5 |
z; |
/* strictly conforming C90 */ |
6/* constraint violation C99 */
f(); /* strictly conforming C90 */ /* constraint violation C99 */
bit-field int
C++
The list of combinations, given above as being new in C99 are not supported by C++.
Like C99, the C++ Standard does not require a translator to provide an implicit function declaration returning int (footnote 80) being supplied for a missing type specifier.
The type specifier s _Complex and _Imaginary shall not be used if the implementation does not provide those 1373 complex types.102)
C90
Support for this type specifier is new in C99.
C++
Support for these type specifiers is new in C99 and are not specified as such in the C ++ Standard. The header <complex> defines template classes and associated operations whose behavior provides the same functionality as that provided, in C, for objects declared to have type _Complex. There are no equivalent definitions for _Imaginary.
Semantics
Each of the comma-separated sets designates the same type, except that for bit-fields, it is implementation- 1377 defined whether the specifier int designates the same type as signed int or the same type as unsigned
int.
C90
Each of the above comma-separated sets designates the same type, except that for bit-fields, the type signed int (or signed) may differ from int (or no type specifiers).
C++
Rather than giving a set of possibilities, the C++ Standard lists each combination of specifiers and its associated type (Table 7).
v 1.0b |
September 2, 2005 |
6.7.2.1 Structure and union specifiers 1381
footnote
102
1378 102) 101)Implementations are not required to provide imaginary types. Freestanding implementations are
not required to provide complex types.
C90
Support for complex types is new in C99.
C++
There is no specification for imaginary types (in the <complex> header or otherwise) in the C++ Standard.
6.7.2.1 Structure and union specifiers
1380
struct-or-union-specifier:
struct-or-union identifieropt { struct-declaration-list } struct-or-union identifier
struct-or-union:
struct union
struct-declaration-list: struct-declaration
struct-declaration-list struct-declaration struct-declaration:
specifier-qualifier-list struct-declarator-list ; specifier-qualifier-list:
type-specifier specifier-qualifier-listopt type-qualifier specifier-qualifier-listopt
struct-declarator-list: struct-declarator
struct-declarator-list , struct-declarator struct-declarator:
declarator
declaratoropt : constant-expression
C++
The C++ Standard uses the general term class to refer to these constructs. This usage is also reflected in naming of the nonterminals in the C++ syntax. The production struct-or-union is known as class-key in C++ and also includes the keyword class. The form that omits the brace enclosed list of members is known as an elaborated-type-specifier (7.1.5.3) in C++.
Constraints
1381 A structure or union shall not contain a member with incomplete or function type (hence, a structure shall not contain an instance of itself, but may contain a pointer to an instance of itself), except that the last member of a structure with more than one named member may have incomplete array type;
C90
Support for the exception on the last named member is new in C99.
C++
It is a design feature of C++ that class types can contain incomplete and function types. Source containing instances of such constructs is making use of significant features of C ++ and there is unlikely to be any expectation of being able to successfully process it using a C translator.
The exception on the last named member is new in C99 and this usage is not supported in the C++ Standard.
The following describes a restriction in C++ that does not apply in C.
struct/union syntax
member not types
September 2, 2005 |
v 1.0b |
annex C.1.7p3 |
|
1385 6.7.2.1 Structure and union specifiers
bit-field maximum width
Change: In C++, a typedef name may not be redefined in a class declaration after being used in the declaration
Example:
typedef int I; struct S {
I i;
int I; // valid C, invalid C++ };
Rationale: When classes become complicated, allowing such a redefinition after the type has been used can create confusion for C++ programmers as to what the meaning of ’I’ really is.
The expression that specifies the width of a bit-field shall be an integer constant expression that has a 1383 nonnegative value that shall not exceed the numberwidth of bits in an object of the type that iswould be specified ifwere the colon and expression are omitted.
C90
The C90 wording ended with “ . . . of bits in an ordinary object of compatible type.”, which begs the question of whether bit-fields are variants of integer types or are separate types.
C++
bit-field |
571 |
The C++ issues are discussed elsewhere. |
|
value is m bits |
|
|
|
|
|
|
1384 |
|
|
If the value is zero, the declaration shall have no declarator. |
C++
9.6p2
Only when declaring an unnamed bit-field may the constant-expression be a value equal to zero.
Source developed using a C++ translator may contain a declaration of a zero width bit-field that include a declarator, which will generate a constraint violation if processed by a C translator.
1struct {
2int mem_1;
3 |
unsigned int mem_2:0; // |
no |
diagnostic required |
|
4 |
/* constraint violation, |
diagnostic required |
*/ |
|
5 |
} obj; |
|
|
|
There is an open C++ DR (#057) concerning the lack of a prohibition against declarations of the form:
1 union {int : 0;} x;
bit-field |
A bit-field shall have a type that is a qualified or unqualified version of _Bool, signed int, unsigned int, or 1385 |
shall have type |
some other implementation-defined type. |
|
|
|
C90 |
|
The following wording appeared in a semantics clause in C90, not a constraint clause. |
v 1.0b |
September 2, 2005 |
6.7.2.1 Structure and union specifiers 1397
A bit-field shall have a type that is a qualified or unqualified version of one of int, unsigned int, or signed int.
Programs that used other types in the declaration of a bit-field exhibited undefined behavior in C90. Such programs exhibit implementation-defined behavior in C99.
C++
9.6p3
A bit-field shall have integral or enumeration type (3.9.1).
Source developed using a C++ translator may contain bit-fields declared using types that are a constraint violation if processed by a C translator.
1enum E_TAG {a, b};
2
3struct {
4 char m_1 : 3;
5short m_2 : 5;
6 long m_3 : 7;
7enum E_TAG m_4 : 9;
8} glob;
Semantics
1386 As discussed in 6.2.5, a structure is a type consisting of a sequence of members, whose storage is allocated in an ordered sequence, and a union is a type consisting of a sequence of members whose storage overlap.
C++
This requirement can be deduced from 9.2p12 and 9.5p1.
1387 Structure and union specifiers have the same form.
C++
The C++ Standard does not make this observation.
1391 If the struct-declaration-list contains no named members, the behavior is undefined.
C++
9p1
An object of a class consists of a (possibly empty) sequence of members and base class objects.
Source developed using a C++ translator may contain class types having no members. This usage will result in undefined behavior when processed by a C translator.
1393 A member of a structure or union may have any object type other than a variably modified type. 103) |
struct member |
|
type |
C90 |
|
Support for variably modified types is new in C99.
C++
Support for variably modified types is new in C99 and they are not specified in the C++ Standard.
September 2, 2005 |
v 1.0b |
1412 |
6.7.2.1 Structure and union specifiers |
|
|||
|
|
|
|
|
|
bit-field |
A bit-field is interpreted as a signed or unsigned integer type consisting of the specified number of bits. 105) |
1397 |
|||
interpreted as |
|
C++
bit-field packed into
The C++ Standard does not specify (9.6p1) that the specified number of bits is used for the value representation.
If the value 0 or 1 is stored into a nonzero-width bit-field of type _Bool, the value of the bit-field shall compare 1398 equal to the value stored.
C90
Support for the type _Bool is new in C99.
If enough space remains, a bit-field that immediately follows another bit-field in a structure shall be packed 1400 into adjacent bits of the same unit.
C++
This requirement is not specified in the C ++ Standard.
9.6p1
Allocation of bit-fields within a class object is implementation-defined.
alignment |
The alignment of the addressable storage unit is unspecified. |
1403 |
addressable |
C++ |
|
storage unit |
|
footnote 103
footnote 105
member alignment
The wording in the C++ Standard refers to the bit-field, not the addressable allocation unit in which it resides. Does this wording refer to the alignment within the addressable allocation unit?
9.6p1
Alignment of bit-fields is implementation-defined. Bit-fields are packed into some addressable allocation unit.
103) A structure or union can not contain a member with a variably modified type because member names |
1406 |
|
are not ordinary identifiers as defined in 6.2.3. |
|
|
C90 |
|
|
Support for variably modified types is new in C99. |
|
|
C++ |
|
|
Variably modified types are new in C99 and are not available in C++. |
|
|
|
|
|
105) As specified in 6.7.2 above, if the actual type specifier used is int or a typedef-name defined as int, |
1409 |
|
then it is implementation-defined whether the bit-field is signed or unsigned. |
|
|
C90 |
|
|
This footnote is new in C99. |
|
|
|
|
|
Each non-bit-field member of a structure or union object is aligned in an implementation-defined manner |
1411 |
|
appropriate to its type. |
|
C++
The C++ Standard specifies (3.9p5) that the alignment of all object types is implementation-defined.
v 1.0b |
September 2, 2005 |
|
6.7.2.1 Structure and union specifiers |
|
1419 |
||
|
|
|
|
|
|
|
|
|
|
|
|
1412 |
Within a structure object, the non-bit-field members and the units in which bit-fields reside have addresses |
|
member |
||
|
that increase in the order in which they are declared. |
address in- |
|||
|
|
creasing |
|||
|
C++ |
|
|
||
|
The C++ Standard does not say anything explicit about bit-fields (9.2p12). |
|
|
||
|
|
|
|
|
|
1414 |
There may be unnamed padding within a structure object, but not at its beginning. |
|
structure |
||
|
|
|
unnamed padding |
||
|
C90 |
|
|
There may therefore be unnamed padding within a structure object, but not at its beginning, as necessary to achieve the appropriate alignment.
C++
This commentary applies to POD-struct types (9.2p17) in C++. Such types correspond to the structure types available in C.
1417 A pointer to a union object, suitably converted, points to each of its members (or if a member is a bit-field, then to the unit in which it resides), and vice versa.
C++
union members start same address
This requirement can be deduced from:
9.5p1
Each data member is allocated as if it were the sole member of a struct.
1418 There may be unnamed padding at the end of a structure or union. |
structure |
|
C++ |
trailing padding |
|
|
||
The only time this possibility is mentioned in the C++ Standard is under the sizeof operator: |
|
|
|
|
5.3.3p2 |
|
When applied to a class, the result is the number of bytes in an object of that class including any padding |
|
|
|
|
|
required for placing objects of that type in an array. |
|
|
|
|
1419 As a special case, the last element of a structure with more than one named member may have an incomplete array type;
C90
The issues involved in making use of the struct hack were raised in DR #051. The response pointed out declaring the member to be an array containing fewer elements and then allocating storage extra storage for additional elements was not strictly conforming. However, declaring the array to have a large number of elements and allocating storage for fewer elements was strictly conforming.
1#include <stdlib.h>
2#define HUGE_ARR 10000 /* Largest desired array. */
3
4 struct A {
September 2, 2005 |
v 1.0b |