Affected subclause: [dcl.stc]
Change:
In C++, the
static or
extern specifiers can only be applied to names of objects or functions
.
Using these specifiers with type declarations is illegal in C++
. In C, these specifiers are ignored when used on type declarations
.Example:
static struct S {
int i;
};
Rationale:
Storage class specifiers don't have any meaning when associated
with a type
. In C++, class members can be declared with the
static storage
class specifier
. Allowing storage class specifiers on type
declarations could render the code confusing for users
. Effect on original feature:
Deletion of semantically well-defined feature
. Difficulty of converting:
Syntactic transformation
. Affected subclause: [dcl.typedef]
Change:
A C++ typedef name 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)
. In C, a typedef name and a struct tag name declared in the same scope
can have the same name (because they have different name spaces)
.Example:
typedef struct name1 { } name1;
struct name { };
typedef int name;
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
. Example:
class name { };
name i;
Effect on original feature:
Deletion of semantically well-defined feature
. Difficulty of converting:
Semantic transformation
. One of the 2 types has to be renamed
. Affected subclause: [dcl.type]
Change:
Banning implicit
int. In the following example, the
left-hand column presents valid C;
the right-hand column presents
equivalent C++:
void f(const parm); void f(const int parm);
const n = 3; const int n = 3;
main() int main()
Rationale:
In C++, implicit int creates several opportunities for
ambiguity between expressions involving function-like
casts and declarations
. Explicit declaration is increasingly considered
to be proper style
. Liaison with WG14 (C) indicated support for (at least)
deprecating implicit int in the next revision of C
. Effect on original feature:
Deletion of semantically well-defined feature
. Difficulty of converting:
Syntactic transformation
. Affected subclause: [dcl.fct]
Change:
In C++, a function declared with an empty parameter list takes no arguments
. In C, an empty parameter list means that the number and type of the function arguments are unknown
.Example:
int f();
Rationale:
This is to avoid erroneous function calls (i.e., function calls
with the wrong number or type of arguments)
. Effect on original feature:
Change to semantics of well-defined feature
. This feature was marked as “obsolescent” in C
. Difficulty of converting:
Syntactic transformation
. The function declarations using C incomplete declaration style must
be completed to become full prototype declarations
. 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
. Change:
In C++, types may not be defined in return or parameter types
. In C, these type definitions are allowed
.Example:
void f( struct S { int a; } arg ) {}
enum E { A, B, C } f() {}
Rationale:
When comparing types in different translation units, C++ relies
on name equivalence when C relies on structural equivalence
. 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
. Effect on original feature:
Deletion of semantically well-defined feature
. Difficulty of converting:
Semantic transformation
. The type definitions must be moved to file scope, or in header files
. This style of type definition is seen as poor coding style
. Affected subclause: [dcl.fct.def]
Change:
In C++, the syntax for function definition excludes the “old-style” C function
. In C, “old-style” syntax is allowed, but deprecated as “obsolescent”
. Rationale:
Prototypes are essential to type safety
. Effect on original feature:
Deletion of semantically well-defined feature
. Difficulty of converting:
Syntactic transformation
. How widely used:
Common in old programs, but already known to be obsolescent
. Affected subclause: [dcl.init.aggr]
Change:
In C++, designated initialization support is restricted
compared to the corresponding functionality in C
. 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
.Example:
struct A { int x, y; };
struct B { struct A a; };
struct A a = {.y = 1, .x = 2};
int arr[3] = {[1] = 5};
struct B b = {.a.x = 0};
struct A c = {.x = 1, 2};
Rationale:
In C++, members are destroyed in reverse construction order
and the elements of an initializer list are evaluated in lexical order,
so field initializers must be specified in order
. Nested designators are seldom used
. Effect on original feature:
Deletion of feature that is incompatible with C++
. Difficulty of converting:
Syntactic transformation
. How widely used:
Out-of-order initializers are common
. The other features are seldom used
. Affected subclause: [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
. In C, an array can be initialized with a string even if
the array is not large enough to contain the string-terminating
'\0'.Example:
char array[4] = "abcd";
Rationale:
When these non-terminated arrays are manipulated by standard
string functions, there is potential for major catastrophe
. Effect on original feature:
Deletion of semantically well-defined feature
. Difficulty of converting:
Semantic transformation
. The arrays must be declared one element bigger to contain the
string terminating
'\0'. This style of array initialization is seen as poor coding style
. Affected subclause: [dcl.enum]
Change:
C++ objects of enumeration type can only be assigned values of the same enumeration type
. In C, objects of enumeration type can be assigned values of any integral type
.Example:
enum color { red, blue, green };
enum color c = 1;
Rationale:
The type-safe nature of C++
. Effect on original feature:
Deletion of semantically well-defined feature
. Difficulty of converting:
Syntactic transformation
. (The type error produced by the assignment can be automatically
corrected by applying an explicit cast
.)
Affected subclause: [dcl.enum]
Change:
In C++, the type of an enumerator is its enumeration
. In C, the type of an enumerator is
int.Example:
enum e { A };
sizeof(A) == sizeof(int)
sizeof(A) == sizeof(e)
Rationale:
In C++, an enumeration is a distinct type
. Effect on original feature:
Change to semantics of well-defined feature
. Difficulty of converting:
Semantic transformation
. The only time this affects existing C code is when the size of an
enumerator is taken
. Taking the size of an enumerator is not a
common C coding practice
.