Annex C (informative) Compatibility [diff]

C.1 C++ and ISO C [diff.iso]

C.1.8 [class]: classes [diff.class]

[class.name] [see also [dcl.typedef]]
Change: In C++, a class declaration introduces the class name into the scope where it is declared and hides any object, function or other declaration of that name in an enclosing scope.
In C, an inner scope declaration of a struct tag name never hides the name of an object or function in an outer scope.
Example:
int x[99];
void f() {
  struct x { int a; };
  sizeof(x);  /* size of the array in C */
  /* size of the struct in C++ */
}

Rationale: This is one of the few incompatibilities between C and C++ that can be attributed to the new C++ name space definition where a name can be declared as a type and as a non-type in a single scope causing the non-type name to hide the type name and requiring that the keywords class, struct, union or enum be used to refer to the type name.
This new name space definition provides important notational conveniences to C++ programmers and helps making the use of the user-defined types as similar as possible to the use of fundamental types.
The advantages of the new name space definition were judged to outweigh by far the incompatibility with C described above.

Effect on original feature: Change to semantics of well-defined feature.

Difficulty of converting: Semantic transformation.
If the hidden name that needs to be accessed is at global scope, the ​::​ C++ operator can be used.
If the hidden name is at block scope, either the type or the struct tag has to be renamed.

How widely used: Seldom.
[class.bit]
Change: Bit-fields of type plain int are signed.

Rationale: Leaving the choice of signedness to implementations could lead to inconsistent definitions of template specializations.
For consistency, the implementation freedom was eliminated for non-dependent types, too.

Effect on original feature: The choice is implementation-defined in C, but not so in C++.

Difficulty of converting: Syntactic transformation.

How widely used: Seldom.
[class.nest]
Change: In C++, the name of a nested class is local to its enclosing class.
In C the name of the nested class belongs to the same scope as the name of the outermost enclosing class.
Example:
struct X {
  struct Y { /* ... */ } y;
};
struct Y yy;                    // valid C, invalid C++

Rationale: C++ classes have member functions which require that classes establish scopes.
The C rule would leave classes as an incomplete scope mechanism which would prevent C++ programmers from maintaining locality within a class.
A coherent set of scope rules for C++ based on the C rule would be very complicated and C++ programmers would be unable to predict reliably the meanings of nontrivial examples involving nested or local functions.

Effect on original feature: Change to semantics of well-defined feature.

Difficulty of converting: Semantic transformation.
To make the struct type name visible in the scope of the enclosing struct, the struct tag could be declared in the scope of the enclosing struct, before the enclosing struct is defined.
Example:
struct Y;                       // struct Y and struct X are at the same scope
struct X {
  struct Y { /* ... */ } y;
};
All the definitions of C struct types enclosed in other struct definitions and accessed outside the scope of the enclosing struct could be exported to the scope of the enclosing struct.
Note: this is a consequence of the difference in scope rules, which is documented in [basic.scope].

How widely used: Seldom.
[class.nested.type]
Change: In C++, a typedef name may not be redeclared in a class definition after being used in that definition.
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.

Effect on original feature: Deletion of semantically well-defined feature.

Difficulty of converting: Semantic transformation.
Either the type or the struct member has to be renamed.

How widely used: Seldom.