0

In this code:

const int* const fun(const int *const ptr)
{
    return ptr;
}

int main()
{
    int i=9;
    int *main_ptr;
    main_ptr = fun(&i);
    return 0;
}

The compiler warns:

warning: assignment discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers] main_ptr = fun(&i);

On defining main_ptr as a pointer to const int the warning goes away (which is understandable) but compiler doesn't complain about discarding const qualifier while degrading from a const pointer to just a pointer.

Is this behavior of warning in one case and no warning in other because of the fact that when it come to pointer to const int in this case the variable being pointed is not destroyed when the function fun ends and due to the same reason the const pointer to int part doesn't matter as the variable is local and it gets destroyed when fun gets over?

Agrudge Amicus
  • 1,033
  • 7
  • 19
  • 2
    "compiler doesn't complain about discarding `const` qualifier while degrading from a `const` pointer to `int` to a just a pointer to `int`." I don't understand what you mean. Where does this happen where the compiler does not issue a warning? – jamesdlin Apr 28 '20 at 03:32
  • You also talk about `const int`, but there is nothing of type `const int` in your code. – jamesdlin Apr 28 '20 at 03:33
  • @jamesdlin Its **pointer** to `const int`, the compiler doesn't issue a warning/error when a `const` pointer is degraded to just a pointer. – Agrudge Amicus Apr 28 '20 at 03:36
  • @AgrudgeAmicus Function arguments are passed by value, so there is no chance for `fun` to modify `main_ptr`, and therefore there is no possible const violation to warn of. This has nothing to do with "*variable being pointed is not destroyed*", which I am not sure what even means in this context. – dxiv Apr 28 '20 at 03:41
  • @AgrudgeAmicus The warning you cited *is* complaining that you're converting a `const T*` (pointer to `const`) to `T*`. Or by "`const` pointer", do you mean a `T* const`? That'd be no different from assigning a `const int` to an `int`. – jamesdlin Apr 28 '20 at 03:45
  • @AgrudgeAmicus "*while degrading from a const pointer to just a pointer.*" - What and where shall be this "*degrading*" process you´re talking about? This doesn´t match to your provided code. Do you want us to pick in the dark? Please create a [Minimal Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example). – RobertS supports Monica Cellio Apr 28 '20 at 07:53
  • Also, for the same reason, no warning in `int foo = /* (const) */ 42;` – pmg Apr 28 '20 at 08:29
  • `main_ptr = fun(&i);` is `main_ptr` const? You are attempting to assign and `const int *` to `int *` -- thus the warning `assignment discards ‘const’ qualifier` – David C. Rankin Apr 28 '20 at 08:31

2 Answers2

2

Qualifiers (const, volatile, restricted, and _Atomic) apply only to lvalues (designators of objects in memory), not to values (data in expressions). Per C 2018 6.7.3 5:

The properties associated with qualified types are meaningful only for expressions that are lvalues.

Consider const int x = 3; int y = x;. This is allowed. The const is a restriction on x. Once the value of x is read, the result is just the int 3; there is no const attached to the 3. Then we may set the value of y to 3, and there is no requirement that y not change after that. const does not stick with the value, and the compiler will not warn us about this.

The declaration const int* const fun(const int *const ptr) says the value returned by fun is const. That is meaningless, and a good compiler could warn that the const just before fun has no effect. Regardless, this qualifier is discarded when evaluating the function call, so there is no problem in assigning the return value of this function to a pointer that is not const.

We can consider a simpler example:

int t;
const int * const x = &t;
const int *       y = x;

The compiler does not warn about this because y receives only the value of x. The fact that x may not change does not impede our ability to assign its value to y, which can change.

Supplement

When an lvalue is used for its value in an expression, all its qualifiers are discarded. C 2018 6.3.2.1 2 says:

Except when it is the operand of the sizeof operator, the unary & operator, the ++ operator, the -- operator, or the left operand of the . operator or an assignment operator, an lvalue that does not have array type is converted to the value stored in the designated object (and is no longer an lvalue); this is called lvalue conversion. If the lvalue has qualified type, the value has the unqualified version of the type of the lvalue; …

Each qualifier says something about how an object in memory will be treated:

  • const says the object in memory will not be modified (through this lvalue).
  • volatile says the object in memory can change by means unknown to the C implementation or that accessing it can cause effects unknown to the C compiler.
  • restrict says the object in memory will only be accessed by means derived from that particular lvalue.
  • _Atomic says accesses to the object in memory behave as if it were one indivisible thing (not made of bytes that can be read or modified separately), so that accesses from multiple threads always use a “whole” value for it, never mixing partial accesses from different threads.
Community
  • 1
  • 1
Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
0

There are two type "mismatches" at play here, the first being

main_ptr = fun(...)    // const int *const -> int *

where we are discarding the constness of the return value of fun by assigning it to main_ptr, and the second being

... = fun(&i)          // int * -> const int *const

where we are passing in a plain old int * into a function that takes a const int *const.

As you have noticed, you will be warned when performing the first one because we are losing a safety guarantee that the return type of fun made.

The second one is not an issue because we are gaining a safety guarantee during the execution of fun that the parameter is pointing to a constant integer. In reality, the parameter does not refer to a constant int, but there is no harm in adding more restrictive const qualifiers. There is danger in removing them, so you get a warning for the first situation.

Brian Tracy
  • 6,801
  • 2
  • 33
  • 48
  • The question is particularly about why the second `const` of `const int * const fun(const int *const ptr)` may be discarded. Essentially, it asks why `int t; const int * const x = &t; const int * y = x;` does not produce an error. This answer does not address that. – Eric Postpischil Apr 28 '20 at 10:18
  • @EricPostpischil Thanks for the clarification. At the time of my answer, it was difficult to determine what the question was asking. Also, where do you pull your C standard quotes from? Is there a searchable copy of the standard you know of? – Brian Tracy Apr 28 '20 at 16:59
  • I purchased a copy of the 2018 standard. Information about official and draft versions is [here](https://stackoverflow.com/questions/81656/where-do-i-find-the-current-c-or-c-standard-documents). – Eric Postpischil Apr 28 '20 at 17:15