MaxPowers
MaxPowers

Reputation: 5486

Passing structure to parameter of type `const struct` does not produce a warning

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

Answers (1)

Eric Postpischil
Eric Postpischil

Reputation: 223747

Converting Pointers

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 Structures

I 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.

Footnote

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

Related Questions