[diff.expr] # Annex C (informative) Compatibility [[diff]](./#diff) ## C.7 C++ and C [[diff.iso]](diff.iso#diff.expr) ### C.7.4 [[expr]](expr "7 Expressions"): expressions [diff.expr] [1](#1) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/compatibility.tex#L2966) **Affected subclause:** [[conv.ptr]](conv.ptr) **Change:** Converting void* to a pointer-to-object type requires casting[.](#1.sentence-1) [*Example [1](#example-1)*: char a[10];void* b=a;void foo() {char* c=b;} C accepts this usage of pointer to void being assigned to a pointer to object type[.](#1.sentence-2) C++ does not[.](#1.sentence-3) — *end example*] **Rationale:** C++ tries harder than C to enforce compile-time type safety[.](#1.sentence-4) **Effect on original feature:** Deletion of semantically well-defined feature[.](#1.sentence-5) **Difficulty of converting:** Can be automated[.](#1.sentence-6) Violations will be diagnosed by the C++ translator[.](#1.sentence-7) The fix is to add a cast[.](#1.sentence-8) [*Example [2](#example-2)*: char* c = (char*) b; — *end example*] **How widely used:** This is fairly widely used but it is good programming practice to add the cast when assigning pointer-to-void to pointer-to-object[.](#1.sentence-9) Some C translators will give a warning if the cast is not used[.](#1.sentence-10) [2](#2) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/compatibility.tex#L3002) **Affected subclause:** [[expr.arith.conv]](expr.arith.conv) **Change:** Operations mixing a value of an enumeration type and a value of a different enumeration type or of a floating-point type are not valid[.](#2.sentence-1) [*Example [3](#example-3)*: enum E1 { e };enum E2 { f };int b = e <= 3.7; // valid in C; ill-formed in C++int k = f - e; // valid in C; ill-formed in C++int x = 1 ? e : f; // valid in C; ill-formed in C++ — *end example*] **Rationale:** Reinforcing type safety in C++[.](#2.sentence-2) **Effect on original feature:** Well-formed C code will not compile with this International Standard[.](#2.sentence-3) **Difficulty of converting:** Violations will be diagnosed by the C++ translator[.](#2.sentence-4) The original behavior can be restored with a cast or integral promotion[.](#2.sentence-5) [*Example [4](#example-4)*: enum E1 { e };enum E2 { f };int b = (int)e <= 3.7;int k = +f - e; — *end example*] **How widely used:** Uncommon[.](#2.sentence-6) [3](#3) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/compatibility.tex#L3033) **Affected subclauses:** [[expr.post.incr]](expr.post.incr) and [[expr.pre.incr]](expr.pre.incr) **Change:** Decrement operator is not allowed with bool operand[.](#3.sentence-1) **Rationale:** Feature with surprising semantics[.](#3.sentence-2) **Effect on original feature:** A valid C expression utilizing the decrement operator on a bool lvalue (for instance, via the C typedef in [](stdbool.h.syn#header:%3cstdbool.h%3e "17.15.5 Header synopsis [stdbool.h.syn]")) is ill-formed in C++[.](#3.sentence-3) [4](#4) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/compatibility.tex#L3044) **Affected subclauses:** [[expr.sizeof]](expr.sizeof) and [[expr.cast]](expr.cast) **Change:** In C++, types can only be defined in declarations, not in expressions[.](#4.sentence-1) In C, a sizeof expression or cast expression may define a new type[.](#4.sentence-2) [*Example [5](#example-5)*: p = (void*)(struct x {int i;} *)0; defines a new type, struct x[.](#4.sentence-3) — *end example*] **Rationale:** This prohibition helps to clarify the location of definitions in the source code[.](#4.sentence-4) **Effect on original feature:** Deletion of semantically well-defined feature[.](#4.sentence-5) **Difficulty of converting:** Syntactic transformation[.](#4.sentence-6) **How widely used:** Seldom[.](#4.sentence-7) [5](#5) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/compatibility.tex#L3064) **Affected subclauses:** [[expr.rel]](expr.rel) and [[expr.eq]](expr.eq) **Change:** C allows directly comparing two objects of array type; C++ does not[.](#5.sentence-1) **Rationale:** The behavior is confusing because it compares not the contents of the two arrays, but their addresses[.](#5.sentence-2) **Effect on original feature:** Deletion of semantically well-defined feature that had unspecified behavior in common use cases[.](#5.sentence-3) **Difficulty of converting:** Violations will be diagnosed by the C++ translator[.](#5.sentence-4) The original behavior can be replicated by explicitly casting either array to a pointer, such as by using a unary +[.](#5.sentence-5) [*Example [6](#example-6)*: int arr1[5];int arr2[5];int same = arr1 == arr2; // valid C, ill-formed C++int idem = arr1 == +arr2; // valid in both C and C++ — *end example*] **How widely used:** Rare[.](#5.sentence-6) [6](#6) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/compatibility.tex#L3088) **Affected subclauses:** [[expr.cond]](expr.cond), [[expr.assign]](expr.assign), and [[expr.comma]](expr.comma) **Change:** The result of a conditional expression, an assignment expression, or a comma expression may be an lvalue[.](#6.sentence-1) **Rationale:** C++ is an object-oriented language, placing relatively more emphasis on lvalues[.](#6.sentence-2) For example, function calls may yield lvalues[.](#6.sentence-3) **Effect on original feature:** Change to semantics of well-defined feature[.](#6.sentence-4) Some C expressions that implicitly rely on lvalue-to-rvalue conversions will yield different results[.](#6.sentence-5) [*Example [7](#example-7)*: char arr[100];sizeof(0, arr) yields100 in C++ andsizeof(char*) in C[.](#6.sentence-6) — *end example*] **Difficulty of converting:** Programs must add explicit casts to the appropriate rvalue[.](#6.sentence-7) **How widely used:** Rare[.](#6.sentence-8)