Duplicate const qualifier allowed in C but not in C++?
C99 §6.7.3/4:
If the same qualifier appears more than once in the same specifier-qualifier-list, either directly or via one or more typedef s, the behavior is the same as if it appeared only once.
Yes, that is valid C99, and your discovery is correct.
What is the purpose of const qualifier if I can modify it through a pointer in C?
The reason you could modify the value is because you did a pointer typecast that stripped off the const
ness:
int *p = (int *)&a;
This typecasts a const int*
(namely &a
) to an int *
, allowing you to freely modify the variable. Normally the compiler would warn you about this, but the explicit typecast suppressed the warning.
The main rationale behind const
at all is to prevent you from accidentally modifying something that you promised not to. It's not sacrosanct, as you've seen, and you can cast away const
ness with impunity, much in the same way that you can do other unsafe things like converting pointers to integers or vice-versa. The idea is that you should try your best not to mess with const
, and the compiler will warn you if you do. Of course, adding in a cast tells the compiler "I know what I'm doing," and so in your case the above doesn't generate any sort of warnings.
Is it legal to have multiple const qualifiers?
I think this is ill-formed. [dcl.type]/2
As a general rule, at most one defining-type-specifier is allowed in
the complete decl-specifier-seq of a declaration or in a
defining-type-specifier-seq, and at most one type-specifier is allowed
in a type-specifier-seq. The only exceptions to this rule are the
following:
const
can be combined with any type specifier except itself.- ...
So it's not allowed to repeat const
literally like const const int a = 5;
. (PS redundant cv-qualifications introduced by typedefs are allowed and would be ignored).
Why can a const value not be changed in C++ but in C?
Given your error, the actual program must have been the following:
#include<stdio.h>
main()
{
const int i=5;
int *p;
p=&i;
*p=8;
printf("%d",i);
}
This produces a warning with gcc:
warning: assignment discards 'const' qualifier from pointer target type
and an error with g++:
error: invalid conversion from 'const int*' to 'int*'
So, let's change the title of your question to a better one:
Why does C allow conversion from
const int *
toint *
, but C++ doesn't?
The reason why one gives a warning and another gives an error is not because one allows you to discard const
qualifier and the other doesn't. It's merely because the C standard leaves such incorrect actions as undefined behavior, while the C++ standard specifically marks it as an error. Either way, doing this is wrong.
You can read this similar question asking why this is possible in C.
Is it possible to change value of variable assigned with const qualifier
That's simply how C works.
As far as I know variables declared with a const qualifier are stored in a read only mode
Declaring a variable as constant only prevents you from modifying it via that variable. There's nothing that prevents you from modifying it via a pointer to non-const, pointing at that variable.
Please suggest me a method in which I can't change value of a variable even by using pointers to it.
Sorry to say it, but the answer is choose another language. If you're going to code C, you have to deal with these kind of stuff often.
One thing to do is to instead declare a pointer to const. You can change int * ptr = &var
to const int * ptr = &var
. This would make impossible to modify the value in var
via ptr
, but that is about as far as protection in C goes. You can never write protect the data itself. You can only make sure that the access vectors (my own term in lack of a better one) are forbidden to change the data.
You can also use #define
. It has it's pros and cons, but it does the job.
Another thing you can do to make it harder (but not impossible) to modify the data is to hide data structures. You can see an example of that in this question
A very quirky and certainly NOT recommended way is to use string literals. Here is an example:
const uint32_t const * ptr = (uint32_t*)"\x00\x01\x00\x00";
This will give you a "constant" that has the value 256. At least on my machine. I suspect that you will have to know if your machine is big or little endian. It has three different protections. You cannot make this pointer to point to anything else, you cannot use the pointer to change what it is pointing at, and the data is probably in read only memory. Compilers usually puts string literals in read only memory, but they are not required to do so. I suspect that this is undefined behavior. In short, don't do this. It's just a demonstration of what you might have to do in C to get the code relatively but not completely safe.
What is the difference between the const qualifier in C and the const qualifier in C++?
The most important difference is that in C++ a
const
variable is a constant expression (even prior the introduction of C++11constexpr
), but aconst
variable in C is not.Meaning that C++ allows you to do things like
const size_t n = 1; static int array[n];
but C does not allow that, supposedly for historical reasons.In C++,
const
plays part in determining linkage. This is different between C++ versions. According to cppreference.com (emphasis mine):Any of the following names declared at namespace scope have internal linkage:
- non-volatile non-template (since C++14) non-inline (since C++17) non-exported (since C++20) const-qualified variables (including constexpr) that aren't declared extern and aren't previously declared to have external linkage;
Whereas in C,
const
does not play part in determining linkage at all - only declaration scope and storage class specifiers matter.In C++, you can
const
qualify member functions. This isn't possible in C since it doesn't have syntax support for member functions.C allows
const
-qualified variables to be declared without an initializer. In C, we can writeconst int x;
without initializers, but C++ does not allow that. At a glance, this may seem like a senseless language bug in C, but the rationale is that computers have read-only hardware registers with values set by hardware, not software. Meaning that C remains suitable for hardware-related programming.
c - const pointer to const data (gcc - duplicate 'const' declaration specifier)
You seems have some miss understanding about const, for example.
#include <stdio.h>
int main()
{
int a=123, b=456;
const int *pa = &a;
pa = &b; //legal
*pa = 4; //illegal
printf("a=%d\n", a);
return 0;
}
gcc will give an error saying that
x.c: In function ‘main’:
x.c:8:9: error: assignment of read-only location ‘*pa’
*pa = 4;
^
for your purpose, if I understand correctly, you should define the function as
const struct userData * getEEPROMDataAtIndex(uint32_t uidIndex);
//this const declare the returned pointer point to something cannot be changed
then when you initiate your constant pointer by call this function
const struct userData * const myp = getEEPROMDataAtIndex(index);
// ^ this declare the pointer itself (myp) cannot be changed
Hope this helps.
Deep Analysis of Const Qualifier in C
The keyword const
indicates a variable that is read-only (i.e., cannot be changed at run-time). It does not indicate a compile-time constant. Therefore, all of the usual attributes of variables apply; specifically, it is allocated addressable storage space.
Unlike with #define
, your constant is not necessarily inlined by the compiler. Rather, the compiler will create a symbol corresponding to your const
declaration in the object file so that it can be accessed from other code files—remember that const
objects have external linkage by default in C (although some compilers will still inline the constant value within the file where it is defined).
The reason the code snippet that you posted "works" is because the unary operator &
can be applied to any lvalue, which includes a const
object. Though the behavior here is undefined, I suspect that your compiler is detecting this usage and ensuring that your const
declaration is given address space, and therefore not inlining it, even within the file it is declared.
EDIT: Also see: http://publications.gbdirect.co.uk/c_book/chapter8/const_and_volatile.html
Let's look at what is meant when const
is used. It's really quite simple:
const means that something is not
modifiable, so a data object that is
declared with const as a part of its
type specification must not be
assigned to in any way during the run
of a program. It is very likely that
the definition of the object will
contain an initializer (otherwise,
since you can't assign to it, how
would it ever get a value?), but this
is not always the case. For example,
if you were accessing a hardware port
at a fixed memory address and promised
only to read from it, then it would be
declared to be const but not
initialized.
Taking the address of a
data object of a type which isn't
const and putting it into a pointer to
the const-qualified version of the
same type is both safe and explicitly
permitted; you will be able to use the
pointer to inspect the object, but not
modify it. Putting the address of a
const type into a pointer to the
unqualified type is much more
dangerous and consequently prohibited
(although you can get around this by
using a cast). For example...
Why we cannot create an array with a constant in c
In C:20
is a constant.unsigned int const size_of_list
is not a constant.
Title: "Why we cannot create an array with a constant in c" does not apply to this code.
const char* list_of_words[size_of_list] = {"Some", "Array"}; // Bad
An issue here (and the error message) is why a VLA cannot be initialized. That is answered here.
With a constant, array initialization works fine.
const char* list_of_words[20] = {"Some", "Array"}; // Good
Another issue is mistaking that const
makes an object a constant. It does not.
Alternative C code
int main(){
// unsigned int const size_of_list = 20;
#define size_of_list 20u
const char* list_of_words[size_of_list] = {"Some", "Array"};
for (unsigned int writing_index = 0; writing_index < size_of_list; writing_index ++)
;
return 0;
}
If you can specify the size in the array itself, then you can get it's size with the sizeof
operator. This may be better suited for having the compiler count up the size instead manual counting. When not using C99
VLAs, sizeof
also yields a compile-time constant.
#include <stddef.h> /* size_t */
int main(void) {
const char* list_of_words[] = {"Some", "Array"};
const char list_of_char[sizeof list_of_words
/ sizeof *list_of_words] = {'S','A'};
const size_t size_of_list
= sizeof list_of_words / sizeof *list_of_words;
for (size_t writing_index = 0;
writing_index < size_of_list; writing_index ++);
return 0;
}
Related Topics
Const Method That Modifies *This Without Const_Cast
Understanding Lapack Calls in C++ with a Simple Example
Can You Start a Class Name with a Numeric Digit
So_Rcvtime and So_Rcvtimeo Not Affecting Boost.Asio Operations
Code Runs 6 Times Slower with 2 Threads Than with 1
Stl Container with Std::Unique_Ptr's VS Boost::Ptr_Container
How to Vertically Align Text in Edit Box
How to Get the Starting/Base Address of a Process in C++
Understanding Rvalue References
What Should the 'Pop()' Method Return When the Stack Is Empty
Why Is Taking the Address of a Temporary Illegal
Simulating Mouse Clicks on MAC Os X Does Not Work for Some Applications
String Comparison with the Most Similar String