Ali Baba
Ali Baba

Reputation: 43

Assignment of const to non-const in C

In the following:

struct adt { void * A; };

int new_adt(const void * const A)
{
    struct adt * r = malloc(sizeof(struct adt));
    r->A = A;
}

I get:

warning: assignment discards qualifiers from pointer target type


I know I can use

memcpy(&(r->A), &A, sizeof(void *));

to workaround it, but I must ask: Is there any alternative?

By using const void * const I pretend to say that no changes will be made to the input. Also, now that I think of it, const void * would suffice, wouldn't it? (Since I can't change the pointer so that it affects the caller)

Thanks for taking the time to read.

Upvotes: 4

Views: 9993

Answers (3)

John Bartholomew
John Bartholomew

Reputation: 6586

If you never want to modify A through its pointer from adt, then you should make that pointer const as well, i.e.:

struct adt {
    const void * A;
};

That will make the error go away.

If you do want to modify A through adt, then new_adt should take a non-const pointer.


Edit: A more general note, which may help:

The const keyword, in general, applies to the type immediately to its left. However, if there is no type to its left, it will apply to the type to the right. So: const int * A is the same as int const * A (the const applies to the int, not to the pointer), but in int * const A, the const applies to the pointer, not to the int.

There is a more comprehensive explanation on Wikipedia: const-correctness. The 'Pointers and References' section of that page includes an example which covers the various combinations of const and non-const that you can apply to a pointer.

Upvotes: 6

johne
johne

Reputation: 6770

By using const void * const I pretend to say that no changes will be made to the input.

You have not pretended to say that no changes will be made to the input, you have explicitly told the compiler that you have guaranteed that no changes will be made to the input.

You MUST NOT do what you are doing.

Upvotes: 7

vanza
vanza

Reputation: 9903

You can cast the const away:

r->A = (void *) A;

The issue, though, is less about how to avoid the warning and more about what you're trying to do. The compiler is warning you because you're telling the compiler that "A" is not writable, but you're trying to store it in a location that defines it as writable. That's generally not OK, semantically.

Imagine that "A" points to a location in your binaries data section; trying to write to it, after casting the const away, will most probably cause a segfault.

So, really, think about what you're trying to do more closely before trying to work around the compiler warning. They're warnings for a good reason.

Upvotes: 3

Related Questions