What is the difference in const-correctness between C and C++?
Asked Answered
M

3

73

I understand what const correctness means and my question is not about what const correctness is. So I am not expecting an explanation or C++-FAQ links for that.

My questions are:

  • What are the semantic differences between const in C and const in C++? and
  • What is the reason for the difference?

Quotes from the respective standards which make the differences clear would be nice to have.

I regularly switch between C and C++ and I would like to know the important points that one should keep in mind while doing so.

I don't seem to remember the reason for these (special thanks if you can provide a reasoning) but from the top of my mind, I can remember:

  • const variables in C++ have internal linkage by default, while in C they have default external linkage;
  • const objects can be used as compile-time values in C++, but cannot be used as compile-time values in C;
  • Pointers to string literals must be an char const* in C++ but in C it can be char*.

What am I missing?

Mehitable answered 18/1, 2012 at 9:48 Comment(10)
Pointer to an String literals must be an const in c++: do you mean char *const or char const*?Pickerel
@Als: In early days of C, there was no const, so many programs were written assuming that "Hello, World" was of type char[] when it is of type char const[] (and thus decays to char const*. I think most compilers just didn't want to force people adding const everywhere (by default), but the -pedantic flag should report those violations.Backwoodsman
@Matthieu: Also, those are only actually violations on a C++11 implementation. In C++03 there's a deprecated conversion from narrow string literals to char* (4.2/2), which as far as I can see has been removed in C++11. So C++03 string literals were of type "array of n const char", but nevertheless could decay to char*. Implementations don't have to warn about use of deprecated features, although gcc does by default since -Wwrite-strings is on by default for C++.Kirakiran
@MatthieuM.: String literals are still of type char[] in C.Pinko
@Als: how much do you want to get into? In the libraries, for example, C++ has separate const and non-const versions of strchr and friends, while C doesn't. The reason is that C doesn't have function overloading and can't be bothered with defining two different functions, so instead it has a single const-incorrect function. Does that count as a difference between constants in C and C++?Kirakiran
@SteveJessop: I agree the Question is a bit open ended.My motive behind the Q is to identify the differences which might usually matter/make a substantial difference when switching to & fro between C/C++. For ex: Many a programers are blissfully unaware of the const char *.Knowing the semantics behind why the difference(as you quoted) would really help.I am not looking at utility library functions differences per se which c++ has been forced to modify for its own semantics.Mehitable
"const objects can be used as compile-time values in C++, but cannot be used as compile-time values in C"? In C, const int=3; can compile into a literal in assembly. This contradicts this claim (or I misunderstand it).Anomalous
@ugoren: the compiler is allowed to use the value if it knows it, but the language does not permit a const int variable in the places that a constant value is called for (such as for the size of a non-VLA array, or the value of a case label). C++ defines "integer constant expressions" for such purposes, and a const-qualified object with a visible definition is permitted in addition to the things that C permits (just literals and enum values, I think, and arithmetic expressions involving only them).Kirakiran
@ugoren: Consider: const int n = 5; struct x { int f : n; }; int main() {}. This is valid C++, not valid C.Whiny
I know this is an old question, but I just made a small edit to it. It referred to "constants" in C and C++, but the question is actually about const, which is a different thing. const really means "read-only", whereas a constant is a literal, and a constant expression is one that can be evaluated at compile time. (Although in C++, but not in C, a const declaration can create a constant expression; for example, given const int x = 42;, the identifier x is a constant expression in C++.)Primm
L
35

In addition to the differences you cite, and the library differences that Steve Jessop mentions,

char* p1;
char const* const* p2 = &p1;

is legal in C++, but not in C. Historically, this is because C originally allowed:

char* p1;
char const** p2 = &p1;

Shortly before the standard was adopted, someone realized that this punched a hole in const safety (since *p2 can now be assigned a char const*, which results in p1 being assigned a char const*); with no real time to analyse the problem in depth, the C committee banned any additional const other than top level const. (I.e. &p1 can be assigned to a char ** or a char **const, but not to a char const** nor a char const* const*.) The C++ committee did the further analysis, realized that the problem was only present when a const level was followed by a non-const level, and worked out the necessary wording. (See §4.4/4 in the standard.)

Libertine answered 18/1, 2012 at 11:20 Comment(5)
@Atalie They break const-correctness because they allow an expression which modifies a const object without an explicit type conversion: int const i = 42; int const* pi = &i; int* pi2; int const** ppi = &pi2; pii = pi; *pi2 = 0;. The last line breaks const-correctness. This example was discovered at the very end of C standardization; as a result, C banned all implicit addition of top level const. When standardizing C++, one person did a more complete analysis, and the rule was liberalized to allow adding top level const as long as all nested levels were also const.Libertine
Damn, once again I got tricked by the misleading formatting (there really ought to be a space before the star in const*)... just after pointing it out. Shame on me.Atalie
Why not write const int i = 42? You keep saying int const i = 42 but no one will write like that.Stuccowork
Regarding your 4 upvoted comment: I assume you meant const int i = 42; const int *pi = &i; int *pi2; const int **ppi = &pi2; ppi = π *pi2 = 0; (should be ppi not pii, there is no pii) when you wrote pii, and it's ppi = &pi not ppi = pi since they're pointer to different targets, const in * for ppi and const int for pi, respectively.Stuccowork
const int i = 42; is inconsistent. The coding guidelines where I current work recommend int const i = 42;, and that's been the form I've encountered most frequently over the last 20 years.Libertine
W
12

In C const declarations do not produce constant expressions, i.e. in C you can't use a const int object in a case label, as a bit-field width or as array size in a non-VLA array declaration (all this is possible in C++). Also, const objects have external linkage by default in C (internal linkage in C++). Const-correctness rules of C++ language support the following standard conversion

int **pp = 0;
const int *const *cpp = pp; // OK in C++

int ***ppp = 0;
int *const *const *cppp = ppp; // OK in C++

These will not work in c.

Whirlabout answered 18/1, 2012 at 11:6 Comment(1)
In C, if I have void f(void **p);, I can't do const int *x; f(&x); (if f used the return value instead of an output parameter, there would be no problem). Does your example mean this code is OK in C++?Anomalous
P
8

The reason for some of these differences is to allow us to get rid of preprocessor macros, which was one of Bjarne's early design goals.

In C we might have

 #define MAX_FOOS 10
 int foos[MAX_FOOS];

In C++ we'd prefer to be able to write

 const int max_foos = 10;
 int foos[max_foos];

For that to work max_foos needs to be usable in a constant expression. It also needs to have internal linkage, so the definition can appear in a header without causing multiple definition errors, and more importantly to make it easier for the compiler to not allocate any storage for max_foos.

When the C committee adopted const from C++ they didn't adopt the antipathy to macros, so they didn't need these semantics.

Purington answered 19/1, 2012 at 8:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.