Note: I put this list together by searching for 'const' in Annex C of
the C++ standard.
Forgot about that. Yes, that is an unfortunate difference, and
I'll never figure out why C++ has this inconsistency.
As a result of that rule, such names qualify as constant expressions in
C++. In particular, if they refer to an object with integer type, they
qualify as integral constant expressions.
That would not be the case in C, where "constant expression" doesn't
include such identifiers.
Where's the difference here. Neither language allows implicit
conversions of pointer to const to pointer to non-const,
regardless of the types involved.
Annex C of the C++ standard says that this is a difference, which rather
surprised me at first. However, when I checked it out, I found that
section 6.3.2.3p1 of the C standard says that "A pointer to any
incomplete or object type may be converted to a pointer to void...",
without imposing any restrictions on the qualification of that pointer
type. Section 6.3.2.3p2 allows conversions that increase the
qualification of pointer types other than 'void*'; there's no
corresponding clause that allows conversions that decrease the
qualification for types other than 'void*'; but for void*, conversions
in both directions are allowed.
In C++, in contrast, there is no special exception for void*, and
section 4.4 only permits pointer conversions that add qualifiers.
I think that what you're thinking of are the constraints on implicit
conversions that occur during pointer assignments involving void*, which
require the the left operand have all of the qualifiers of the right
operand. The implicit conversions that occur when passing an argument to
a prototyped function, and when returning from a function, are also
subject to those same constraints, since they are both described as
occurring "as if by assignment".
However, pointer comparisons are not subject to qualification-based
constraints. In C the comparison of an unqualified void* with a
qualified pointer to an object or incomplete type involves the allowed
implicit conversion of the qualified pointer to void*.
Such a comparison is also allowed in C++, but it does not involve the
disallowed implicit conversion to void*. Instead, it is performed by
implicit conversion of the void* pointer to the type of the other
operand. In C, it wouldn't really matter whether the pointers were
converted to void* or to the other pointer's type. However, in C++, I
think that this distinction might determine whether
MyType:
perator(void*)() or MyType::MyType(void*) is called. If it
doesn't the whole issue is a moot point.
It might be better for C++ Annex C to describe this as a difference in
how pointer comparisons involving void* are carried out.
> There is a difference not
concerning const: C allows implicit conversion of void* to T*
(where T is any other type), C++ doesn't. And there is a subtle
case involving pointers to pointers: C doesn't allow char** ->
char const* const*, whereas C++ does. (Neither allow char** ->
char const**, since this would break const.)
Granted. But is there any scenario where you wouldn't
initialize them in C?
In order for such constants to be of any use, they would have to have
static storage duration, and would therefore be zero-initialized, which
would only make sense if zero-initialization would give them the desired
value. This has no obvious advantage over the integer literal 0 for
scalar types.
However, I've actually used precisely this technique to create a named
const static object of struct type, which I would copy into a
dynamically allocated structure to zero-initialize it. The struct
contained both pointer and floating point members, which might, in
principle, not have been correctly zero-initialized if I had used
calloc() or memset().