Reputation: 4732
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
.
Upvotes: 0
Views: 277
Reputation: 3141
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
.
Upvotes: 1
Reputation: 222274
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
.
Upvotes: 0
Reputation: 289
You can wrap another function to do it.
int wrapfun() {
int var;
func(..., &var);
return var;
}
int main()
{
const int var = wrapfun();
}
Upvotes: 1