303
303

Reputation: 4732

Const type qualifier when doing pointer things

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

Answers (3)

JayK
JayK

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

Eric Postpischil
Eric Postpischil

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

phy nju
phy nju

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

Related Questions