This question may be naive, but:
is there const keyword in C?
since which version?
are there any semantic and/or syntactic differences between const in C and C++?
There are no syntactic differences between C and C++ with regard to const keyword, besides a rather obscure one: in C (since C99) you can declare function parameters as
void foo(int a[const]);
which is equivalent to
void foo(int *const a);
declaration. C++ does not support such syntax.
Semantic differences exist as well. As #Ben Voigt already noted, 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++).
There's at least one more semantic difference, which Ben did not mention. 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 initializations are illegal in C.
int **pp = 0;
const int *const *cpp = pp; /* ERROR in C */
int ***ppp = 0;
int *const *const *cppp = ppp; /* ERROR in C */
Generally, when dealing with multi-level pointers, C++ says that you can add const-qualification at any depth of indirection, as long as you also add const-qualification all the way to the top level.
In C you can only add const-qualification to the type pointed by the top-level pointer, but no deeper.
int **pp = 0;
int *const *cpp = pp; /* OK in C */
int ***ppp = 0;
int **const *cppp = ppp; /* OK in C */
Another manifestation of the same underlying general principle is the way const-correctness rules work with arrays in C and C++. In C++ you can do
int a[10];
const int (*p)[10] = &a; // OK in C++
Trying to do the same in C will result in an error
int a[10];
const int (*p)[10] = &a; /* ERROR in C */
The first two questions are answered here: Const in C
Yes there are quite a few differences in semantics between const in C and C++.
In C++, const variables of appropriate type are integral constant expressions (if their initializers are compile-time constant expressions) and can be used in context which requires that, such as array bounds, and in enum definitions. In C, they are not and cannot be.
In C++, const global variables automatically have static linkage, so you can put them in header files. In C, such variables have external linkage and that would generate duplicate definition errors at link time.
Yes, there is a const keyword. It was added as part of the 1989 standard.
As far as compatibility, here's a paragraph from Harbison & Steele, 5th edition:
A top-level declaration that has the type qualifier const but no explicit storage class is considered to be static in C++ but extern in C. To remain compatible, examine top-level const declarations and provide an explicit storage class.
In C++, string constants are implicitly const; they are not in C.
Yes, const has been there since at least since ANSI C (aka C89).
It certainly appears in my copy of "The C Programming Language (2nd Edition)", Kernighan & Ritchie (published in 1988).
Relevant extract:
The const and volatile properties are new with the ANSI standard. The purpose of const is to
announce objects that may be placed in read-only memory, and perhaps to increase opportunities for
optimization.
Two other differences:
const arraytype (i.e typedef int A[1]; const A a = { 0 };) specifies a constant array type ( http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#112 and http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1059 ) (and whose elements are so-qualified too) in C++, but a non-constant array type whose elements are so-qualified in C.
const const is valid in C99 (not valid in C89), not valid in C++ in any version (you can only semantically repeat a const, not syntactically). It contracts to const in C99.
Yes. const is there in C, from C89.
Here is a good read is about behaviour of const keyword in C.
The semantic in C is different than in C++. For example,
unsigned const a = 10;
unsigned A[a];
in file scope would be valid in C++, but not in C.
Yes, there's a const keyword in C. It's been there since C90.
Syntactically, it can occur in the same places as in C++. Semantically, it's a bit more lax, IIRC.
According to ESR, const was added in the ANSI C Draft Proposed Standard. Eric Giguere's summary of ANSI C, dated 1987, confirms it.
This looks like the draft itself -- search for "3.5.3 Type qualifiers".
There is a "const" keyword in C, and it has been for a long time. If a variable is designated "const", writes to it are forbidden.
Additionally, in some environments, variables declared "const" may be located in a different data segment from other variables. This data segment may offer hardware write protection, and for embedded systems, may be stored in ROM or flash memory rather than in RAM (a very important distinction on some processors which have a lot more ROM or flash than RAM--e.g. 128 KB flash and 3.5 KB RAM, or 2 KB ROM and 96 bytes RAM).
Note that the compiler will generally not make any inferences about "const" values or expressions involving them. If I say "const char foo[] = "Hello";" and then later make reference to foo[1], the compiler will load the value (which will most likely be 'e') from wherever foo[] is stored and use the loaded value. Sometimes this usefully allows values to be patched in a compiled code image, but sometimes it just wastes code.
If you want to define a number to to be a compile-time "substitutable" constant, the best way, at least for integer constants, may be to use "enum". For example, "enum {woozle=19;}" will cause 19 to be substituted for "woozle" throughout the code. Note that unlike textual substitutions; enum declarations obey proper rules of scope.
Related
Suppose I'm using some C library which has a function:
int foo(char* str);
and I know for a fact that foo() does not modify the memory pointed to by str. It's just poorly written and doesn't bother to declare str being constant.
Now, in my C++ code, I currently have:
extern "C" int foo(char* str);
and I use it like so:
foo(const_cast<char*>("Hello world"));
My question: Is it safe - in principle, from a language-lawyering perspective, and in practice - for me to write:
extern "C" int foo(const char* str);
and skip the const_cast'ing?
If it is not safe, please explain why.
Note: I am specifically interested in the case of C++98 code (yes, woe is me), so if you're assuming a later version of the language standard, please say so.
Is it safe for me to write: and skip the const_cast'ing?
No.
If it is not safe, please explain why.
-- From language side:
After reading the dcl.link I think exactly how the interoperability works between C and C++ is not exactly specified, with many "no diagnostic required" cases. The most important part is:
Two declarations for a function with C language linkage with the same function name (ignoring the namespace names that qualify it) that appear in different namespace scopes refer to the same function.
Because they refer to the same function, I believe a sane assumption would be that the declaration of a identifier with C language linkage on C++ side has to be compatible with the declaration of that symbol on C side. In C++ there is no concept of "compatible types", in C++ two declarations have to be identical (after transformations), making the restriction actually more strict.
From C++ side, we read c++draft basic#link-11:
After all adjustments of types (during which typedefs are replaced by their definitions), the types specified by all declarations referring to a given variable or function shall be identical, [...]
Because the declaration int foo(const char *str) with C language linkage in a C++ translation unit is not identical to the declaration int foo(char *str) declared in C translation unit (thus it has C language linkage), the behavior is undefined (with famous "no diagnostic required").
From C side (I think this is not even needed - the C++ side is enough to make the program have undefined behavior. anyway), the most important part would be C99 6.7.5.3p15:
For two function types to be compatible, both shall specify compatible return types. Moreover, the parameter type lists, if both are present, shall agree in the number of parameters and in use of the ellipsis terminator; corresponding parameters shall have compatible types [...]
Because from C99 6.7.5.1p2:
For two pointer types to be compatible, both shall be identically qualified and both shall be pointers to compatible types.
and C99 6.7.3p9:
For two qualified types to be compatible, both shall have the identically qualified version of a compatible type [...]
So because char is not compatible with const char, thus const char * is not compatible with char *, thus int foo(const char *) is not compatible with int foo(char*). Calling such a function (C99 6.5.2.2p9) would be undefined behavior (you may see also C99 J.2)
-- From practical side:
I do not believe will be able to find a compiler+architecture combination where one translation unit sees int foo(const char *) and the other translation unit defines a function int foo(char *) { /* some stuff */ } and it would "not work".
Theoretically, an insane implementation may use a different register to pass a const char* argument and a different one to pass a char* argument, which I hope would be well documented in that insane architecture ABI and compiler. If that's so, wrong registers will be used for parameters, it will "not work".
Still, using a simple wrapper costs nothing:
static inline int foo2(const char *var) {
return foo(static_cast<char*>(var));
}
I think the base answer is:
Yes, you can cast off const even if the referenced object is itself const such as a string literal in the example.
Undefined behaviour is only specified to arise in the event of an attempt to modify the const object not as a result of the cast.
Those rules and their reason to exist is 'old'. I'm sure they predate C++98.
Contrast it with volatile where any attempt to access a volatile object through a non-volatile reference is undefined behaviour. I can only read 'access' as read and/or write here.
I won't repeat the other suggestions but here is the most paranoid solution.
It's paranoid not because the C++ semantics aren't clear. They are clear. At least if you accept something being undefined behaviour is clear!
But you've described it as 'poorly written' and you want to put some sandbags round it!
The paranoid solution relies on the fact that if you are passing a constant object it will be constant for the whole execution (if the program doesn't risk UB).
So make a single copy of "hello world" lower in the call-stack or even initialised as a file scope object. You can declare it static in a function and it will (with minimal overhead) only be constructed once.
This recovers almost all of the benefits of string literal. The lower down the call stack including file-scope (global you put it the better.
I don't know how long the lifetime of the pointed-to object passed to foo() needs to be.
So it needs to be at least low enough in the chain to satisfy that condition.
NB: C++98 has std::string but it won't quite do here because you're still forbidden for modifying the result of c_str().
Here the semantics are defined.
#include <cstring>
#include <iostream>
class pseudo_const{
public:
pseudo_const(const char*const cstr): str(NULL){
const size_t sz=strlen(cstr)+1;
str=new char[sz];
memcpy(str,cstr,sz);
}
//Returns a pointer to a life-time permanent copy of
//the string passed to the constructor.
//Modifying the string through this value will be reflected in all
// subsequent calls.
char* get_constlike() const {
return str;
}
~pseudo_const(){
delete [] str;
}
private:
char* str;
};
const pseudo_const str("hello world");
int main() {
std::cout << str.get_constlike() << std::endl;
return 0;
}
I have some concepts about the VLA and its behavior that I need to clarify.
AFIK since C99 it's possible to declare VLA into local scopes:
int main(int argc, char **argv)
{
// function 'main' scope
int size = 100;
int array[size];
return 0;
}
But it is forbidden in global scopes:
const int global_size = 100;
int global_array[global_size]; // forbidden in C99, allowed in C++
int main(int argc, char **argv)
{
int local_size = 100;
int local_array[local_size];
return 0;
}
The code above declares a VLA in C99 because the const modifier doesn't create a compile-time value. In C++ global_size is a compile-time value so, global_array doesn't become a VLA.
What I need to know is: Is my reasoning correct? Is the behaviour that I've described correct?
I also want to know: Why are the VLA not allowed in global scope? are they forbidden both in C and C++? Why is the behavior of arrays into global and local scope different?
Yes your reasoning is correct, that is how these different forms of array declarations and definitions are viewed by C and C++.
As others already stated, VLA with a veritable variable length (non-const) in global scope is difficult to make sense. What would the evaluation order be, e.g if the the length expression would refer to an object of a different compilation unit? C++ doesn't have VLA, but it has dynamic initialization of objects at file scope. And already this gives you quite a head ache, if you have to rely on evaluation order.
This leaves the small gap for C concerning length expressions that contain a const qualified object, which isn't allowed. This comes from the fact that such objects are not considered "integer constant expressions" by the C standard. This could perhaps change in future versions, but up to now the C committee didn't find it necessary to allow for such a thing: there are enum constants that play that role in C. Their only limitation is that they are limited to int in C, it would be nice to also have them size_t.
C++ doesn't support VLAs, period. The reason the second code snippet works in C++ is that the const keyword creates a compile-time constant in C++; in C, it doesn't.
C99 doesn't support VLAs outside of block scope, period, regardless of how you declare the size variable. Note that C2011 makes VLA support optional.
There is a difference between being forbidden and not being allowed. ;-)
The VLA feature is designed to allow the use of stack space for a local array, to avoid the use of malloc for heap allocation. It is mostly a speed optimization.
Now you want to use VLAs outside of functions. Why? There is not much to win speedwise in avoiding a single malloc call during program start. And what stack space are we supposed to use for variables with a static life time?
I think the fundamental reason is a global variable has linkage, its size has to be known at compile time. If not, how could one link the program?
local variables have no linkage and the VLAs are allocated on the stack, which grows dynamically as the program runs.
So, for global VLA's, one of the issues (there are many variants on the theme) can be shown here:
int size;
int a;
int v[size];
int b;
....
in another file:
extern int a;
extern int b;
The linker will have to know where a and be are in relation to each other at link time, or it won't be able to fix them up correctly at load-time.
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?
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.)
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.
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.
What is the difference between:
const variable = 10;
and
const int variable = 10;
Does variable, per the standard, get interpreted as an integral type when no type is defined?
const variable = 10 is not valid C++, while const int variable = 10; is.
The only time (that I can think of) that const variable = 10 would be valid is if you had a type named variable and you had a function with an unnamed parameter of that type, taking a default argument:
typedef int variable;
void foo(const variable = 10);
It means that x is implicitly declared an int. This is not allowed in C++, but in C and to maintain compatibility with C headers or pre-ISO C++ code, a lot of contemporary C++compilers still support this as an option.
My GCC 4.4 compiler here groks "const x=3;" when feed -fms-extensions on the command line (the manual says, that it turns on a couple of lamps which are required to understand MFC code)
UPDATE: I've checked it with VS-2005, you can have implicit int if you use
#pragma warning(disable:4430)
const variable = 10;
won't compile in almost all new moderns C++ compilers.
With no strict rules (K&R C etc. Edit : i.e. old C), int is the type by default. It certainly does not mean the variable has no type, and it does not have anything to do with const.
struct A {
static const int a = 5;
struct B {
static const int b = a;
};
};
int main() {
return A::B::b;
}
The above code compiles. However if you go by Effective C++ book by Scott Myers(pg 14);
We need a definition for a in addition to the declaration.
Can anyone explain why this is an exception?
C++ compilers allow static const integers (and integers only) to have their value specified at the location they are declared. This is because the variable is essentially not needed, and lives only in the code (it is typically compiled out).
Other variable types (such as static const char*) cannot typically be defined where they are declared, and require a separate definition.
For a tiny bit more explanation, realize that accessing a global variable typically requires making an address reference in the lower-level code. But your global variable is an integer whose size is this typically around the size of an address, and the compiler realizes it will never change, so why bother adding the pointer abstraction?
By really pedantic rules, yes, your code needs a definition for that static integer.
But by practical rules, and what all compilers implement because that's how the rules of C++03 are intended - no, you don't need a definition.
The rules for such static constant integers are intended to allow you to omit the definition if the integer is used only in such situations where a value is immediately read, and if the static member can be used in constant expressions.
In your return statement, the value of the member is immediately read, so you can omit the definition of the static constant integer member if that's the only use of it. The following situation needs a definition, however:
struct A {
static const int a = 5;
struct B {
static const int b = a;
};
};
int main() {
int *p = &A::B::b;
}
No value is read here - but instead the address of it is taken. Therefore, the intent of the C++03 Standard is that you have to provide a definition for the member like the following in some implementation file.
const int A::B::b;
Note that the actual rules appearing in the C++03 Standard says that a definition is not required only where the variable is used where a constant expression is required. That rule, however, if strictly applied, is too strict. It would only allow you to omit a definition for situation like array-dimensions - but would require a definition in cases like a return statement. The corresponding defect report is here.
The wording of C++0x has been updated to include that defect report resolution, and to allow your code as written.
However, if you try the ternary operand without "defining" static consts, you get a linker error in GCC 4x:
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=13795
So, although constructs like int k = A::CONSTVAL; are illegal in the current standard, they are supported. But the ternary operand is not. Some operators are more equal than others, if you get my drift :)
So much for "lax" rules. I suggest you write code conforming to the standard if you do not want surprises.
In general, most (and recent) C++ compilers allow static const ints
You just lucky, perhaps not. Try older compiler, such as gcc 2.0 and it will vehemently punish you with-less-than-pretty error message.