Reputation: 5486
In the following example not-const qualified pointer b
is passed to func
, which expects a pointer to a const qualified type. Hence, I would expect the compiler to issue a warning. However, if I compile this program with clang and -Wall -Wextra -pedantic
there is no warning. Why is that?
#include <stdlib.h>
#include <string.h>
#define N 5
struct Bear {
int n;
int v;
int *data;
};
void func (const struct Bear *bear, int *data, const size_t n)
{
memcpy (bear->data, data, n);
}
int main (void)
{
int arr[N];
int *mem = malloc (N*sizeof (int));
if (mem == NULL) return -1;
struct Bear *b = &(struct Bear){1, 2, mem};
func (b, arr, N);
free (mem);
return 0;
}
Moreover, if I change the line in which the structure is initialized to
const struct Bear *b = &(const struct Bear){1, 2, mem};
there is still no warning. I understand that const
in a struct declaration is applied to its fields, hence, bear->v = 11;
in func
is clearly an error (and produces a warning). However, this does not seem to be true for pointers.
Is this undefined behavior? What am I missing here?
Upvotes: 0
Views: 516
Reputation: 223747
When calling a function with a prototype, the argument (b
, of type struct Bear *
) is converted to the type of the corresponding parameter (bear
, of type const struct Bear *
), per C 2018 6.5.2.2 7:
If the expression that denotes the called function has a type that does include a prototype, the arguments are implicitly converted, as if by assignment, to the types of the corresponding parameters…
The constraints for assignment in 6.5.16.1 1 include allowing conversion to a pointer to the same type but with added qualifiers such as const
:
… the left operand has atomic, qualified, or unqualified pointer type, and … both operands are pointers to qualified or unqualified versions of compatible types, and the type pointed to by the left has all the qualifiers of the type pointed to by the right…
Also, conversions of pointers are discussed in C 2018 6.3.2.3, where paragraph 2 says:
For any qualifier q, a pointer to a non-q-qualified type may be converted to a pointer to the q-qualified version of the type…
Quite simply, the qualifiers are restrictions on the use of a thing; they say it is intended for some subset of potential uses of the thing. The const
qualifier says the object will be used only to read its value, not to modify its value.1 So it is perfectly fine to pass a pointer to a thing that may be modified to a function that indicates it will not modify it. So the rules of the C standard are written to permit this.
const
Applied to StructuresI understand that const in a struct declaration is applied to its fields…
If the structure is const
, the structure member data
is const
, but that member is a pointer. So this just means the pointer is const
. That does not mean what it points to is const
.
1 The const
qualifier is not a complete barrier to modifying an object. If an object was defined without const
, a pointer to it for which const
has been added can be converted (with a cast) back to a pointer without const
and used to modify the object.
Upvotes: 3