Difference in const qualifiers warning - c

I am getting a bunch of warning messages telling me that
Warning C4090 '=': different 'const' qualifiers cA4 c:\users\kyle\documents\visual studio 2015\projects\ca4\ca4\ca4.c 313
I need to compile my code to have no warnings for this school assignment. Everything works okay but I want to know why this is happening. I am assigning a "string" which is really a char* to a value from a const array to keep track of what city they are currently in.
Like so:
char* currentCityName = cityNames[currentCity];
The warning is occurring on this line later in the program:
currentCityName = cityNames[currentCity];
Declaration of cityNames:
const char* cityNames[kNumberOfCities] = { "Toronto", "Atlanta", "Austin", "Santa Fe", "Denver", "Chicago", "Buffalo" };
Clearly some way that I am setting this variable is incorrect and the compiler isnt liking it.
Im looking for an explanation of why this is happening and what I should be doing instead of this.

You say
I am assigning a "string" which is really a char* to a value from a const array
From that and the error message I presume you mean that you have
const char *cityNames[<some bound>];
which is an array of pointers to strings whose contents are const. If you also have
char *currentCityName;
and you later try to perform
currentCityName = cityNames[currentCity];
then the resulting pointer to modifiable characters in fact points to characters that elsewhere are declared const. This mismatch may lead to the program, without any other warning, attempting to modify const data, with undefined results.
You could clear up that warning by instead declaring currentCityName like so:
const char *currentCityName;
to match the true type of the value you want to assign to it. Alternatively, you can make a modifiable copy of the city name, and point currentCityName at that. Making a copy is necessary if you want to (safely) modify the pointed-to data.

I'm assuming that cityNames is declared as const so when you're assigning the value(does not copy contents) it discards the const qualifier.
In other words you cannot change anything in cityNames because of const but you have another pointer, non-const this time and allow you to change data although it was originally marked as const

Related

C pointer to a const - how to quieten warnings

I have an array like this:
const uint8_t Translations[] =
{
0xA6,0xA0,1,0,
0xA1,0x87,2,0,
0xA0,0xBE,3,0,
0,
};
and I would like to access it with a pointer:
uint8_t * p_translations = Translations;
I get the warning:
warning: assigning to 'uint8_t *' from 'const uint8_t *const' discards qualifiers.
I'm fine with that as I only read from and never write to *p_translations.
Is there a way to quieten the compiler (Microchip XC8) without suppressing warnings?
There is usually never a good reason to ever discard the const qualifier, as the warning states. Some possible reasons in the wild are while passing to APIs that expect raw unqualified pointers. If the API doesn't need to change the data pointed to by the pointer, it should have a const in the declaration.
Also, compiler warnings are usually something to aid the developer and are mostly warnings that should be heeded to.
For your case too, there's no reason why p_translations should not be a uint8_t const* if you never intend to modify what p_translations points to. If on the other hand, you had to modify Translations, then you should drop the const altogether from Translations. Use const to indicate entities that shall remain unchanged throughout the program lifecycle. It's perfectly fine to have a non-const array that would be modified, else adopt const. Here is one of many links to read on why const can be helpful apart from indicating the const-ness of the data, namely possible opportunity for compiler optimizations and avoiding writing code that accidentally modifies the data.
You should make your pointer const too, const with pointers mean that the memory region they are pointing to is read-only. That tells compiler that it can do or not do some stuff. In your case(not using const with pointer) compiler understands that as a regular pointer accessing a read-only memory part, and raises a warning, the reason for the warning is you can actually change the const variables using pointers, but you should avoid it at all costs because it's UB and your program might do stuff that it shouldn't. But when you declare your pointer as const it tells compiler to treat it like a const and doesn't allow any writing to that memory region. And keep in mind the declaration you use while creating pointer only tells the compiler what type of data you're pointing to. So it doesn't mean your pointer is not changeable. If you want to make your pointer const you declare it like this type* const ptr. I hope i provided enough help.
You have a warning because you store the address of a const array into a pointer that is not const qualified.
Use const uint8_t *p_translations = Translations; to fix the problem.
Note that const uint8_t *p_translations is equivalent to uint8_t const *p_translations, but different from uint8_t * const p_translations, which is a pointer that cannot be changed and points to data that can be changed through the pointer.
Defining p_translations as const uint8_t *p_translations is a way to tell the compiler that you do not intend to modify the data pointed to by p_translations using this pointer. Since Translations is itself defined as const data, it should only be manipulated through a const qualified pointer to detect code that would try and modify it.

warning: initialization discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]

I am trying to understand why my compiler is warning me about this code:
static const char *const _menuMain_Strings_1[] __ATTR_PROGMEM__ = { _menuMain_L1,
_menuMain_L2, _menuMain_L3, _menuMain_L4 }
static const MENU_DEFINITION _menuDef_Main_1 __ATTR_PROGMEM__ = {
_menuMain_Strings_1, _menuMain_Fields_1 };
../menudefs.h:53:3: warning: initialization discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
53 | _menuMain_Strings_1, _menuMain_Fields_1 };
| ^~~~~~~~~~~~~~~~~~~
At first, I had to add the extra *const in order for it to generate a hex file to remove the compiler error. From my assumption, the compiler is discarding one of the const regardless. How can I satisfy the compiler without it giving me warnings? Thank you.
The error message indicates that _menuMain_Strings_1 identifies a pointer to const data (which it does), but you are using it to initialize a pointer to non-const data. You have not presented all the details of those types, but this is not about the compiler discarding qualifiers. Rather, it is about your code having a const-qualification mismatch.
Such a situation warrants a warning because if the pointed-to data is in fact itself declared const (as opposed to that qualification being only in the pointer) then attempting to modify it produces undefined behavior. The compiler can spot that and reject it when access is through the original, const-qualified pointer, but not when access is through the non-const-qualifed copy with which _menuDef_Main_1 is initialized.
How can I satisfy the compiler without it giving me warnings?
Use const consistently or not at all. And note that it is viral: you can apply const-qualification freely, but you cannot safely remove it. Presumably, you will need to modify the definition of MENU_DEFINITION to carry through const appropriately, and this may require you to make further changes as a result.

Why do we not use const more often?

It is common to see the keyword const with pointers :
void function(const char *string)
{
const char *other_string = "some string";
}
But why do not we use const every time we declare a variable that we will not change ? It is rare to see :
void function(const int i)
{
const double j = 1.2;
// i and j will not be changed in this function
}
I am trying to understand why we do not use const more often, is it always a good thing to use it when we can, or not ?
This post seems to answer YES, but in reality this doest not seem to be the case ...
In most cases it no longer makes a difference.
Often enough the compiler will be able to deduce that the variable is actually read only, and treat it as a constant during optimization.
Either way, you usually use const consequently on things like const char *string in order to avoid accidentally modifying the parameter.
Since all parameters are passed by value, this isn't something which can't happen for an integer. Only for pointers the pointer itself is the value.
Actually, const char *string isn't fully constant either yet. Only the chars the pointer is pointing to is, but the pointer as a variable isn't. It would only become when specifying it as const char * const string. Now the string variable is completely constant for the scope of the function.
In the case you give, I would always say
void function(const int i)
in a situation where the role of i is to parameterise the behaviour of the function -- which is almost always. If I change i in the body of the function, I have either made an error, or written something which another person will find hard to understand later.
Intentionally modifying the value of i in the function isn't as "dangerous" as modifying a entity through its pointer -- it won't create side-effects outside the function. I guess that's why most developers don't feel the pressure to define primitive paramters as const. I maintain, however, that it is a sensible thing to do, if one cares about long-term maintenance.
In your second example, the parameter is passed by value, making it const basicly has no meaning. const is most handy when passing parameters by reference.
There is another problem with const known as "const poisoning". Consider the following:
int foo(char * str, int n)
{
...
bar(str);
...
}
If we make str to be const, we must then ensure that bar also takes a const etc. (which can affect multiple files and modules). This is especially painful if you're editing old and inconsistent code (not always the case, but should be considered).

Declaring a pointer to const or a const pointer to const as a formal parameter

I was recently making some adjustments to code wherein I had to change a formal parameter in a function. Originally, the parameter was similar to the following (note, the structure was typedef'd earlier):
static MySpecialStructure my_special_structure;
static unsigned char char_being_passed; // Passed to function elsewhere.
static MySpecialStructure * p_my_special_structure; // Passed to function elsewhere.
int myFunction (MySpecialStructure * p_structure, unsigned char useful_char)
{
...
}
The change was made because I could define and initialize my_special_structure before compile time and myFunction never changed the value of it. This led to the following change:
static const MySpecialStructure my_special_structure;
static unsigned char char_being_passed; // Passed to function elsewhere.
static MySpecialStructure * p_my_special_structure; // Passed to function elsewhere.
int myFunction (const MySpecialStructure * p_structure, unsigned char useful_char)
{
...
}
I also noticed that when I ran Lint on my program that there were several Info 818's referencing a number of different functions. The info stated that "Pointer parameter 'x' (line 253) could be declared as pointing to const".
Now, I have two questions in regards to the above. First, in regards to the above code, since neither the pointer nor the variables within MySpecialStructure is changed within the function, is it beneficial to declare the pointer as constant as well? e.g. -
int myFunction (const MySpecialStructure * const p_structure, unsigned char useful_char)
My second question is in regards to the Lint information. Are there any benefits or drawbacks to declaring pointers as a constant formal parameter if the function is not changing its value... even if what you are passing to the function is never declared as a constant? e.g. -
static unsigned char my_char;
static unsigned char * p_my_char;
p_my_char = &my_char;
int myFunction (const unsigned char * p_char)
{
...
}
Thanks for your help!
Edited for clarification -
What are the advantages of declaring a pointer to const or a const pointer to const- as a formal parameter? I know that I can do it, but why would I want to... particularly in the case where the pointer being passed and the data it is pointing to are not declared constant?
What are the advantages of declaring a pointer as a const - as a formal parameter? I know that I can do it, but why would I want to... particularly in the case where the pointer being passed and the data it is pointing to are not declared constant?
I assumed you meant a pointer to const.
By have a pointer to const as a parameter, the advantage is you document the API by telling the programmer your function does not modify the object pointed by the pointer.
For example look at memcpy prototype:
void *memcpy(void * restrict s1, const void * restrict s2, size_t n);
It tells the programmer the object pointed to by s2 will not be modified through memcpy call.
It also provides compiler enforced documentation as the implementation will issue a diagnostic if you modify a pointee from a pointer to const.
const also allows to indicate users of your function that you won't modify this parameter behind their back
If you declare a formal parameter as const, the compiler can check that your code does not attempt to modify that parameter, yielding better software quality.
Const correctness is a wonderful thing. For one, it lets the compiler help keep you from making mistakes. An obvious simple case is assigning when you meant to compare. In that instance, if the pointer is const, the compiler will give you an error. Google 'const correctness' and you'll find many resources on the benefits of it.
For your first question, if you are damn sure of not modifying either the pointer or the variable it points to, you can by all means go ahead and make both of them constant!
Now, for your Qn as to why declare a formal pointer parameter as const even though the passed pointer is not constant, A typical use case is library function printf(). printf is supposed to accept const char * but the compiler doesn't complain even if you pass a char* to it. In such a case, it makes sense that printf() doesn't not build upon the user's mistake and alter user's data inadvertantly! Its like printf() clearly telling- Whether you pass a const char * or char*, dont worry, I still wont modify your data!
For your second question, const pointers find excellent application in the embedded world where we generally write to a memory address directly. Here is the detailed explanation
Well, what are the advantages of declaring anything as a const while you have the option to not to do so? After all, if you don't touch it, it doesn't matter if it's const or not. This provides some safety checks that the compiler can do for you, and it gives some information of the function interface. For example, you can safely pass a string literal to a function that expects a const char *, but you need to be careful if the parameter is declared as just a char *.

Protecting a variable's data by const qualifier is of no use !!!?

#include<stdio.h>
int main()
{
const char const_cvar1 = 'X';
const char* ptr_to_const_char = &const_cvar1;
// Simply a typecast of "ptr to a const char" to a "ptr to char" disables security !!!
*(char *)ptr_to_const_char = 'S';
printf("\n Value of const char changed from X to : %c \n", const_cvar1);
return 0;
}
Outputs:-
Value of const char changed from X to : S
I wonder if we can never rely on the const qualifier in C ? is it the fact ?
It's C. You can do a lot of things that are stupid, causes undefined behavior, is compiler/platform dependent etc.
casting away the const modifier is one of them. You are able to do so, but you get little guarantees as to what the result will be.
You could even cast it to just about anything, at your own risk.
*(float *)ptr_to_const_char = 2.18;
However, const is not useless.
It provides documentation, a programmer reading code where a pointer is declared const
can assume he can/should not modify what the pointer points to
It can enable the compiler to do further optimizations
Just keep in mind that C does not protect you against yourself or others, it also gives you the ability to not honor the type system.
It is indeed a fact. In fact, the compiler turns off const optimizations (few as there are) the moment it sees you casting away const, treating it like any other variable.
const does not protect a variable. In fact, const does not even mean the variable will never change.
What it means is that you, the programmer, declare that you won't be writing to that part of memory. A memory-mapped input-only pin on a microchip might be represented by a variable qualified const, but it can still change if the voltage on the pin changes. (In fact, it will most likely be declared const volatile, which blew my mind the first time I saw it.) But the const means that you aren't allowed to write to it.
So if you break that promise — that you have no intention of writing to it — well then yes, of course that'll mess things up.
You are programming in C and its always like that. While playing with pointers you need to be careful always.
I believe you want
char * const ptr_to_const_char
which is a constant pointer, not a pointer to a constant.
But that may only work in C++.
Modifying the content of a variable defined as const using such means is clearly UB. Avoid that.

Resources