495 lines
14 KiB
Markdown
495 lines
14 KiB
Markdown
[diff.dcl]
|
||
|
||
# Annex C (informative) Compatibility [[diff]](./#diff)
|
||
|
||
## C.7 C++ and C [[diff.iso]](diff.iso#diff.dcl)
|
||
|
||
### C.7.6 [[dcl]](dcl "9 Declarations"): declarations [diff.dcl]
|
||
|
||
[1](#1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/compatibility.tex#L3168)
|
||
|
||
**Affected subclause:** [[dcl.stc]](dcl.stc)
|
||
|
||
|
||
**Change:** In C++, the static or extern specifiers can only be applied to names of objects or functions[.](#1.sentence-1)
|
||
|
||
|
||
|
||
|
||
Using these specifiers with type declarations is illegal in C++[.](#1.sentence-2)
|
||
|
||
In C, these specifiers are ignored when used on type declarations[.](#1.sentence-3)
|
||
|
||
[*Example [1](#example-1)*: static struct S { // valid C, invalid in C++int i;}; â *end example*]
|
||
|
||
|
||
|
||
|
||
**Rationale:** Storage class specifiers don't have any meaning when associated
|
||
with a type[.](#1.sentence-4)
|
||
|
||
In C++, class members can be declared with the static storage
|
||
class specifier[.](#1.sentence-5)
|
||
|
||
Storage class specifiers on type
|
||
declarations can be confusing for users[.](#1.sentence-6)
|
||
|
||
|
||
|
||
|
||
**Effect on original feature:** Deletion of semantically well-defined feature[.](#1.sentence-7)
|
||
|
||
|
||
|
||
|
||
**Difficulty of converting:** Syntactic transformation[.](#1.sentence-8)
|
||
|
||
|
||
|
||
|
||
**How widely used:** Seldom[.](#1.sentence-9)
|
||
|
||
[2](#2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/compatibility.tex#L3196)
|
||
|
||
**Affected subclause:** [[dcl.stc]](dcl.stc)
|
||
|
||
|
||
**Change:** In C++, register is not a storage class specifier[.](#2.sentence-1)
|
||
|
||
|
||
|
||
|
||
**Rationale:** The storage class specifier had no effect in C++[.](#2.sentence-2)
|
||
|
||
|
||
|
||
|
||
**Effect on original feature:** Deletion of semantically well-defined feature[.](#2.sentence-3)
|
||
|
||
|
||
|
||
|
||
**Difficulty of converting:** Syntactic transformation[.](#2.sentence-4)
|
||
|
||
|
||
|
||
|
||
**How widely used:** Common[.](#2.sentence-5)
|
||
|
||
[3](#3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/compatibility.tex#L3208)
|
||
|
||
**Affected subclause:** [[dcl.typedef]](dcl.typedef)
|
||
|
||
|
||
**Change:** A C++ [*typedef-name*](dcl.typedef#nt:typedef-name "9.2.4 The typedef specifier [dcl.typedef]") must be different from any class type name declared
|
||
in the same scope (except if the typedef is a synonym of the class name with the
|
||
same name)[.](#3.sentence-1)
|
||
|
||
In C, a [*typedef-name*](dcl.typedef#nt:typedef-name "9.2.4 The typedef specifier [dcl.typedef]") and a struct tag name declared in the same scope
|
||
can have the same name (because they have different name spaces)[.](#3.sentence-2)
|
||
|
||
[*Example [2](#example-2)*: typedef struct name1 { /* ... */ } name1; // valid C and C++struct name { /* ... */ };typedef int name; // valid C, invalid C++ â *end example*]
|
||
|
||
|
||
|
||
|
||
**Rationale:** For ease of use, C++ doesn't require that a type name be prefixed
|
||
with the keywords class, struct or union when used in object
|
||
declarations or type casts[.](#3.sentence-3)
|
||
|
||
[*Example [3](#example-3)*: class name { /* ... */ };
|
||
name i; // i has type class name â *end example*]
|
||
|
||
|
||
|
||
|
||
**Effect on original feature:** Deletion of semantically well-defined feature[.](#3.sentence-4)
|
||
|
||
|
||
|
||
|
||
**Difficulty of converting:** Semantic transformation[.](#3.sentence-5)
|
||
|
||
One of the 2 types has to be renamed[.](#3.sentence-6)
|
||
|
||
|
||
|
||
|
||
**How widely used:** Seldom[.](#3.sentence-7)
|
||
|
||
[4](#4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/compatibility.tex#L3243)
|
||
|
||
**Affected subclause:** [[dcl.type]](dcl.type) [see also [[basic.link]](basic.link "6.7 Program and linkage")]
|
||
|
||
**Change:** Const objects must be initialized in C++ but can be left uninitialized in C[.](#4.sentence-2)
|
||
|
||
**Rationale:** A const object cannot be assigned to so it must be initialized
|
||
to hold a useful value[.](#4.sentence-3)
|
||
|
||
|
||
|
||
|
||
**Effect on original feature:** Deletion of semantically well-defined feature[.](#4.sentence-4)
|
||
|
||
|
||
|
||
|
||
**Difficulty of converting:** Semantic transformation[.](#4.sentence-5)
|
||
|
||
|
||
|
||
|
||
**How widely used:** Seldom[.](#4.sentence-6)
|
||
|
||
[5](#5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/compatibility.tex#L3256)
|
||
|
||
**Affected subclause:** [[dcl.spec.auto]](dcl.spec.auto)
|
||
|
||
|
||
**Change:** The keyword auto cannot be used as a storage class specifier[.](#5.sentence-1)
|
||
|
||
[*Example [4](#example-4)*: void f() {auto int x; // valid C, invalid C++} â *end example*]
|
||
|
||
|
||
|
||
|
||
**Rationale:** Allowing the use of auto to deduce the type
|
||
of a variable from its initializer results in undesired interpretations ofauto as a storage class specifier in certain contexts[.](#5.sentence-2)
|
||
|
||
|
||
|
||
|
||
**Effect on original feature:** Deletion of semantically well-defined feature[.](#5.sentence-3)
|
||
|
||
|
||
|
||
|
||
**Difficulty of converting:** Syntactic transformation[.](#5.sentence-4)
|
||
|
||
|
||
|
||
|
||
**How widely used:** Rare[.](#5.sentence-5)
|
||
|
||
[6](#6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/compatibility.tex#L3279)
|
||
|
||
**Affected subclause:** [[dcl.fct]](dcl.fct)
|
||
|
||
|
||
**Change:** In C++, a function declared with an empty parameter list takes no arguments[.](#6.sentence-1)
|
||
|
||
In C, an empty parameter list means that the number and type of the function arguments are unknown[.](#6.sentence-2)
|
||
|
||
[*Example [5](#example-5)*: int f(); // means int f(void) in C++// int f( unknown ) in C â *end example*]
|
||
|
||
|
||
|
||
|
||
**Rationale:** This is to avoid function calls
|
||
with the wrong number or type of arguments[.](#6.sentence-3)
|
||
|
||
|
||
|
||
|
||
**Effect on original feature:** Change to semantics of well-defined feature[.](#6.sentence-4)
|
||
|
||
This feature was marked as âobsolescentâ in C[.](#6.sentence-5)
|
||
|
||
**Difficulty of converting:** Syntactic transformation[.](#6.sentence-6)
|
||
|
||
The function declarations using C incomplete declaration style must
|
||
be completed to become full prototype declarations[.](#6.sentence-7)
|
||
|
||
A program may need to be updated further if different calls to the
|
||
same (non-prototype) function have different numbers of arguments or
|
||
if the type of corresponding arguments differed[.](#6.sentence-8)
|
||
|
||
|
||
|
||
|
||
**How widely used:** Common[.](#6.sentence-9)
|
||
|
||
[7](#7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/compatibility.tex#L3307)
|
||
|
||
**Affected subclause:** [[dcl.fct]](dcl.fct) [see [[expr.sizeof]](expr.sizeof "7.6.2.5 Sizeof")]
|
||
|
||
**Change:** In C++, types may not be defined in return or parameter types[.](#7.sentence-2)
|
||
|
||
In C, these type definitions are allowed[.](#7.sentence-3)
|
||
|
||
[*Example [6](#example-6)*: void f( struct S { int a; } arg ) {} // valid C, invalid C++enum E { A, B, C } f() {} // valid C, invalid C++ â *end example*]
|
||
|
||
|
||
|
||
|
||
**Rationale:** When comparing types in different translation units, C++ relies
|
||
on name equivalence when C relies on structural equivalence[.](#7.sentence-4)
|
||
|
||
Regarding parameter types: since the type defined in a parameter list
|
||
would be in the scope of the function, the only legal calls in C++
|
||
would be from within the function itself[.](#7.sentence-5)
|
||
|
||
|
||
|
||
|
||
**Effect on original feature:** Deletion of semantically well-defined feature[.](#7.sentence-6)
|
||
|
||
|
||
|
||
|
||
**Difficulty of converting:** Semantic transformation[.](#7.sentence-7)
|
||
|
||
The type definitions must be moved to file scope, or in header files[.](#7.sentence-8)
|
||
|
||
|
||
|
||
|
||
**How widely used:** Seldom[.](#7.sentence-9)
|
||
|
||
This style of type definition is seen as poor coding style[.](#7.sentence-10)
|
||
|
||
[8](#8)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/compatibility.tex#L3334)
|
||
|
||
**Affected subclause:** [[dcl.fct.def]](dcl.fct.def)
|
||
|
||
|
||
**Change:** In C++, the syntax for function definition excludes the âold-styleâ C function[.](#8.sentence-1)
|
||
|
||
In C, âold-styleâ syntax is allowed, but deprecated as âobsolescentâ[.](#8.sentence-2)
|
||
|
||
|
||
|
||
|
||
**Rationale:** Prototypes are essential to type safety[.](#8.sentence-3)
|
||
|
||
|
||
|
||
|
||
**Effect on original feature:** Deletion of semantically well-defined feature[.](#8.sentence-4)
|
||
|
||
|
||
|
||
|
||
**Difficulty of converting:** Syntactic transformation[.](#8.sentence-5)
|
||
|
||
|
||
|
||
|
||
**How widely used:** Common in old programs, but already known to be obsolescent[.](#8.sentence-6)
|
||
|
||
[9](#9)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/compatibility.tex#L3347)
|
||
|
||
**Affected subclause:** [[dcl.init.aggr]](dcl.init.aggr)
|
||
|
||
|
||
**Change:** In C++, designated initialization support is restricted
|
||
compared to the corresponding functionality in C[.](#9.sentence-1)
|
||
|
||
In C++,
|
||
designators for non-static data members
|
||
must be specified in declaration order,
|
||
designators for array elements and nested designators
|
||
are not supported,
|
||
and
|
||
designated and non-designated initializers
|
||
cannot be mixed in the same initializer list[.](#9.sentence-2)
|
||
|
||
[*Example [7](#example-7)*: struct A { int x, y; };struct B { struct A a; };struct A a = {.y = 1, .x = 2}; // valid C, invalid C++int arr[3] = {[1] = 5}; // valid C, invalid C++struct B b = {.a.x = 0}; // valid C, invalid C++struct A c = {.x = 1, 2}; // valid C, invalid C++ â *end example*]
|
||
|
||
|
||
|
||
|
||
**Rationale:** In C++, members are destroyed in reverse construction order
|
||
and the elements of an initializer list are evaluated in lexical order,
|
||
so member initializers must be specified in order[.](#9.sentence-3)
|
||
|
||
Array designators conflict with [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1 General [expr.prim.lambda.general]") syntax[.](#9.sentence-4)
|
||
|
||
Nested designators are seldom used[.](#9.sentence-5)
|
||
|
||
|
||
|
||
|
||
**Effect on original feature:** Deletion of feature that is incompatible with C++[.](#9.sentence-6)
|
||
|
||
|
||
|
||
|
||
**Difficulty of converting:** Syntactic transformation[.](#9.sentence-7)
|
||
|
||
|
||
|
||
|
||
**How widely used:** Out-of-order initializers are common[.](#9.sentence-8)
|
||
|
||
The other features are seldom used[.](#9.sentence-9)
|
||
|
||
[10](#10)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/compatibility.tex#L3384)
|
||
|
||
**Affected subclause:** [[dcl.init.string]](dcl.init.string)
|
||
|
||
|
||
**Change:** In C++, when initializing an array of character with a string, the number of
|
||
characters in the string (including the terminating '\0') must not exceed the
|
||
number of elements in the array[.](#10.sentence-1)
|
||
|
||
In C, an array can be initialized with a string even if
|
||
the array is not large enough to contain the string-terminating '\0'[.](#10.sentence-2)
|
||
|
||
[*Example [8](#example-8)*: char array[4] = "abcd"; // valid C, invalid C++ â *end example*]
|
||
|
||
|
||
|
||
|
||
**Rationale:** When these non-terminated arrays are manipulated by standard
|
||
string functions, there is potential for major catastrophe[.](#10.sentence-3)
|
||
|
||
|
||
|
||
|
||
**Effect on original feature:** Deletion of semantically well-defined feature[.](#10.sentence-4)
|
||
|
||
|
||
|
||
|
||
**Difficulty of converting:** Semantic transformation[.](#10.sentence-5)
|
||
|
||
The arrays must be declared one element bigger to contain the
|
||
string terminating '\0'[.](#10.sentence-6)
|
||
|
||
|
||
|
||
|
||
**How widely used:** Seldom[.](#10.sentence-7)
|
||
|
||
This style of array initialization is seen as poor coding style[.](#10.sentence-8)
|
||
|
||
[11](#11)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/compatibility.tex#L3409)
|
||
|
||
**Affected subclause:** [[dcl.enum]](dcl.enum)
|
||
|
||
|
||
**Change:** C++ objects of enumeration type can only be assigned values of the same enumeration type[.](#11.sentence-1)
|
||
|
||
In C, objects of enumeration type can be assigned values of any integral type[.](#11.sentence-2)
|
||
|
||
[*Example [9](#example-9)*: enum color { red, blue, green };enum color c = 1; // valid C, invalid C++ â *end example*]
|
||
|
||
|
||
|
||
|
||
**Rationale:** The type-safe nature of C++[.](#11.sentence-3)
|
||
|
||
|
||
|
||
|
||
**Effect on original feature:** Deletion of semantically well-defined feature[.](#11.sentence-4)
|
||
|
||
|
||
|
||
|
||
**Difficulty of converting:** Syntactic transformation[.](#11.sentence-5)
|
||
|
||
(The type error produced by the assignment can be automatically
|
||
corrected by applying an explicit cast[.](#11.sentence-6))
|
||
|
||
|
||
|
||
|
||
**How widely used:** Common[.](#11.sentence-7)
|
||
|
||
[12](#12)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/compatibility.tex#L3432)
|
||
|
||
**Affected subclause:** [[dcl.enum]](dcl.enum)
|
||
|
||
|
||
**Change:** In C++, the type of an enumerator is its enumeration[.](#12.sentence-1)
|
||
|
||
In C, the type of an enumerator is int[.](#12.sentence-2)
|
||
|
||
[*Example [10](#example-10)*: enum e { A };sizeof(A) == sizeof(int) // in Csizeof(A) == sizeof(e) // in C++/* and sizeof(int) is not necessarily equal to sizeof(e) */ â *end example*]
|
||
|
||
|
||
|
||
|
||
**Rationale:** In C++, an enumeration is a distinct type[.](#12.sentence-3)
|
||
|
||
|
||
|
||
|
||
**Effect on original feature:** Change to semantics of well-defined feature[.](#12.sentence-4)
|
||
|
||
|
||
|
||
|
||
**Difficulty of converting:** Semantic transformation[.](#12.sentence-5)
|
||
|
||
|
||
|
||
|
||
**How widely used:** Seldom[.](#12.sentence-6)
|
||
|
||
The only time this affects existing C code is when the size of an
|
||
enumerator is taken[.](#12.sentence-7)
|
||
|
||
Taking the size of an enumerator is not a
|
||
common C coding practice[.](#12.sentence-8)
|
||
|
||
[13](#13)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/compatibility.tex#L3458)
|
||
|
||
**Affected subclause:** [[dcl.align]](dcl.align)
|
||
|
||
|
||
**Change:** In C++,
|
||
an [*alignment-specifier*](dcl.attr.grammar#nt:alignment-specifier "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]") is an [*attribute-specifier*](dcl.attr.grammar#nt:attribute-specifier "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]")[.](#13.sentence-1)
|
||
|
||
In C, an [*alignment-specifier*](dcl.attr.grammar#nt:alignment-specifier "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]") is a *declaration-specifier*[.](#13.sentence-2)
|
||
|
||
[*Example [11](#example-11)*: #include <stdalign.h>unsigned alignas(8) int x; // valid C, invalid C++unsigned int y alignas(8); // valid C++, invalid C â *end example*]
|
||
|
||
|
||
|
||
|
||
**Rationale:** C++ requires unambiguous placement of the [*alignment-specifier*](dcl.attr.grammar#nt:alignment-specifier "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]")[.](#13.sentence-3)
|
||
|
||
|
||
|
||
|
||
**Effect on original feature:** Deletion of semantically well-defined feature[.](#13.sentence-4)
|
||
|
||
|
||
|
||
|
||
**Difficulty of converting:** Syntactic transformation[.](#13.sentence-5)
|
||
|
||
|
||
|
||
|
||
**How widely used:** Seldom[.](#13.sentence-6)
|