I have a function as below
void foo(const foo_type* x)
{...}
I am calling this function in other function.
void foo1(int z)
{
foo_type y = z;
foo(&y);
}
This is not throwing any error in c but i feel something is not correct.
What happens when i pass non const variable to function that expects const variable as arguments.
The introduction of const in the way you have is absolutely fine and even desirable.
You have told the compiler explicitly that the function will not modify the parameter passed as const. That could even help with a compiler's optimisation strategy.
The removal of const is, in general, a bad idea though. (Which you're not doing in this case.) The behaviour on modifying a variable via the removal of const that was originally declared as const is undefined.
Related
Let's say I have a local variable int var; that I use for retrieving some value by calling another function, like so: func(..., &var);.
Then I check the retrieved value for certain things and act accordingly. After variable var has received its value, var will never change again from that point on.
Would it then make sense to define var as const? (int const var;).
I'm not sure if that's the correct way to use the const keyword because the initial value of var is something left over from the stack and changes when func is called: func(..., &var);. So, in some way that contradicts the const type qualifier.
The reason that I'm unsure about this is because the effect (or result) of defining variable var as const (int const var;), is the desired behavior for the code that follows within the scope of var.
I.e, it should not be allowed to change the value of var directly with the use of the assignment operator even though the value of var was just changed by some pointer within the func function.
Example
int foo(void)
{
int const var;
if (!func(..., &var))
return 0;
if (var == x)
// do some stuff
else if (var == y)
// do some other stuff
else
// nope
return var * x + y;
}
I wonder if in terms of correctness the const type qualifier for defining var still applies to that situation.
Regarding correctness, at least with gcc you can pass your const var
to the modifying function, but it generates a warning. I would neither
recommend nor do it. It does not help rather than confuse the reader.
It seems that I have stumbled down the wrong path by misinterpreting the resulting behavior of MSVC. While having /Wall enabled, the only warning that MSVC produced was const object should be initialized. Which I didn't think much of because by just initializing var, to see what would happen, the result was a clean compilation.
But I think I have some idea of what is happening, at least. If you have a const data type, the compiler thinks that you should not write to something that is read-only, even when doing so with the use of pointers. So, the only time that it makes sense for the compiler to see the address of a const variable being passed to a function, is when that variable contains anything but a garbage value. Hence the initialization warning.
If var is used in equality comparisons like in your example, making it
const could avoid the if (var = ...) vs. if (var == ...) typo because
the compiler would catch that.
In regard to using const or not when trying to catch this error; I think it has more to do with having the assurance of the compiler spitting something out based on the ruling defined within the standard, than it has with the compiler producing or not producing a warning if const is omitted from the definition of var.
You can wrap another function to do it.
int wrapfun() {
int var;
func(..., &var);
return var;
}
int main()
{
const int var = wrapfun();
}
Expanding on Eric Postpischil's answer, you might also extract the block where var should be const into a new function with var as a const parameter. Whether this makes sense or not depends on what actually happens in that block and how much other dynamic state there is to take care of. I would go with the more readable solution.
If you declare var as const in some parts of the code, you make sure that nobody later inadvertently introduces changes to the code that change the value of var. You would make your intentions for that variable explicit and it might help the reader understand the code. If var is used in equality comparisons like in your example, making it const could avoid the if (var = ...) vs. if (var == ...) typo because the compiler would catch that.
Regarding correctness, at least with gcc you can pass your const var to the modifying function, but it generates a warning. I would neither recommend nor do it. It does not help rather than confuse the reader.
// const.c
#include <stdio.h>
void func(int *var)
{
*var = 5;
}
void post(const int var)
{
printf("%d\n", var);
}
int main(int argc, char *argv[])
{
const int var;
func(&var);
post(var);
return 0;
}
$ gcc const.c
const.c: In function 'main':
const.c:16:10: warning: passing argument 1 of 'func' discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
func(&var);
^
const.c:3:6: note: expected 'int *' but argument is of type 'const int *'
void func(int *var)
^~~~
So in this case, I would go without the const in main, but you could keep it in post.
You can do this, but it is ugly:
int var;
func(..., &var);
{
const int sneaky = var, var = sneaky;
// var is const here.
...
}
This opens a new block, defines sneaky to temporarily hold the value of var, and then defines a new var that hides the old var. Since the old var is hidden, we cannot initialize the new one with the old one, so we initialize the new var with the value we stashed in sneaky.
This question already has answers here:
Const correctness for value parameters
(6 answers)
Closed 6 years ago.
I do understand the meaning of const for pointers or structures that have to be passed by reference to a function. However in the example:
void foo(const int a);
the variable a is passed on the stack. There is no harm to the caller to modify the content of the stack so const looks pretty useless in this situation.
Furthermore, if I cannot modify a, I can still make a copy of a and change this copy:
void foo(const int a)
{
int b = a;
b++;
}
In which situation does the const keyword will be useful when applied to a scalar function argument (not a pointer)?
Code like void foo(const int a) is not really meaningful, nor is it "const correctness" as such.
Sometimes overly pedantic programmers get the weird idea that they need to declare common parameters as const just because a function doesn't modify the actual parameter. But most often, functions do not.
The point is, the variable is a copy of the original, so what your function does with it doesn't matter the slightest!
So this is not even a way of writing self-documenting code, because all it does is to tell the caller what's going on internally inside your function. The caller doesn't care and shouldn't care.
It's unnecessary to use const for a value parameter, but it has its value if what you want is to guarantee the code does what you intend.
Here there's an answer with some example of use cases
It's the same thing as declaring any constant variable
const int size = some_other_variable + 5;
It is a good programming practice to declare variables as const if you know their values will not change. That way from declaration you can avoid that someone accidentally changes their value further down the function.
It means that an implementer of the function cannot change the value of the input parameter a that the function receives by value.
It can lead to increased program stability.
(Personally I dislike the style as I find it too verbose).
If you do adopt this style, then note well that you only need to put the const in the parameter list of the function definition, you don't need it in the declaration.
It's useful mostly for purposes of self-documenting your code.
For future people looking through your source code, the const serves to emphasize your intent (that none of the code in foo() should attempt to modify a).
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 *.
For example:
void func(const int i);
Here,the const is unnecessary since all parameters are passed by value(including pointers).
Is that true?
All parameters in C are indeed passed by value, which means that the actual argument will not change regardless of whether you include that const or not.
However, that does not mean that const here is "never necessary". Whether it is necessary or unnecessary depends on what you want to achieve.
If you want to prevent any attempts to modify the parameter inside the function, then the const is necessary, of course.
There is a fairly popular (and pretty reasonable) coding guideline that says that function parameters should never be modified inside the function, i.e. that at any point of function's execution all parameters must retain their original values. Under this guideline it would actually make perfect sense to always include that const in all parameter declarations.
const is just used by the precompiler, to notice about errors...
Note that this is perfectly valid:
void foo( const char * bar )
{
char * baz = ( char * )bar;
baz++;
}
So it's never necessary, but it just makes the code more readable, and informs you the pointer should never change...
Our static analysis tool complains about a "useless type qualifier on return type" when we have prototypes in header files such as:
const int foo();
We defined it this way because the function is returning a constant that will never change, thinking that the API seemed clearer with const in place.
I feel like this is similar to explicitly initializing global variables to zero for clarity, even though the C standard already states that all globals will be initialized to zero if not explicitly initialized. At the end of the day, it really doesn't matter. (But the static analysis tool doesn't complain about that.)
My question is, is there any reason that this could cause a problem? Should we ignore the errors generated by the tool, or should we placate the tool at the possible cost of a less clear and consistent API? (It returns other const char* constants that the tool doesn't have a problem with.)
It's usually better for your code to describe as accurately as possible what's going on. You're getting this warning because the const in const int foo(); is basically meaningless. The API only seems clearer if you don't know what the const keyword means. Don't overload meaning like that; static is bad enough as it is, and there's no reason to add the potential for more confusion.
const char * means something different than const int does, which is why your tool doesn't complain about it. The former is a pointer to a constant string, meaning any code calling the function returning that type shouldn't try to modify the contents of the string (it might be in ROM for example). In the latter case, the system has no way to enforce that you not make changes to the returned int, so the qualifier is meaningless. A closer parallel to the return types would be:
const int foo();
char * const foo2();
which will both cause your static analysis to give the warning - adding a const qualifier to a return value is a meaningless operation. It only makes sense when you have a a reference parameter (or return type), like your const char * example.
In fact, I just made a little test program, and GCC even explicitly warns about this problem:
test.c:6: warning: type qualifiers ignored on function return type
So it's not just your static analysis program that's complaining.
You can use a different technique to illustrate your intent without making the tools unhappy.
#define CONST_RETURN
CONST_RETURN int foo();
You don't have a problem with const char * because that's declaring a pointer to constant chars, not a constant pointer.
Ignoring the const for now, foo() returns a value. You can do
int x = foo();
and assign the value returned by foo() to the variable x, in much the same way you can do
int x = 42;
to assign the value 42 to variable x.
But you cannot change the 42 ... or the value returned by foo(). Saying that the value returned from foo() cannot be changed, by applying the const keyword to the type of foo() accomplishes nothing.
Values cannot be const (or restrict, or volatile). Only objects can have type qualifiers.
Contrast with
const char *foo();
In this case, foo() returns a pointer to an object. The object pointed to by the value returned can be qualified const.
The int is returned by copy. It may be a copy of a const, but when it is assigned to something else, that something by virtue of the fact that it was assignable, cannot by definition be a const.
The keyword const has specific semantics within the language, whereas here you are misusing it as essentially a comment. Rather than adding clarity, it rather suggests a misunderstanding of the language semantics.
const int foo() is very different from const char* foo(). const char* foo() returns an array (usually a string) whose content is not allowed to change. Think about the difference between:
const char* a = "Hello World";
and
const int b = 1;
a is still a variable and can be assigned to other strings that can't change whereas b is not a variable. So
const char* foo();
const char* a = "Hello World\n";
a = foo();
is allowed but
const int bar();
const int b = 0;
b = bar();
is not allowed, even with the const declaration of bar().
Yes. I would advise writing code "explicitly", because it makes it clear to anyone (including yourself) when reading the code what you meant. You are writing code for other programmers to read, not to please the whims of the compiler and static analysis tools!
(However, you do have to be careful that any such "unnecessary code" does not cause different code to be generated!)
Some examples of explicit coding improving readability/maintainability:
I place brackets around portions of arithmetic expressions to explicitly specify what I want to happen. This makes it clear to any reader what I meant, and saves me having to worry about (or make ay mistakes with) precedence rules:
int a = b + c * d / e + f; // Hard to read- need to know precedence
int a = b + ((c * d) / e) + f; // Easy to read- clear explicit calculations
In C++, if you override a virtual function, then in the derived class you can declare it without mentioning "virtual" at all. Anyone reading the code can't tell that it's a virtual function, which can be disastrously misleading! However you can safely use the virtual keyword: virtual int MyFunc() and this makes it clear to anyone reading your class header that this method is virtual. (This "C++ syntax bug" is fixed in C# by requiring the use of the "override" keyword in this case - more proof if anyone needed it that missing out the "unnecessary virtual" is a really bad idea)
These are both clear examples where adding "unnecessary" code will make the code more readable and less prone to bugs.