7

I always thought that an statement like const int *a means a is an int pointer to const data and as such one should not be able to modify the value it points to. Indeed if you do const int a [] = {1,2,3} and then issue a[0] = 10 you'll get compiler errors.

To my surprise, however, the following compiles without any warning and runs just fine.

#include <stdio.h>
#include <string.h> 

int main (){

    const int a [] = {1, 1, 1};
    const int b [] = {2, 2, 2};

    memcpy((void*) &a[0], (const void*)&b[0], 3*sizeof(int));

    int i;
    for (i=0; i<3; i++) printf("%d\n",a[i]);

    return 0;
} 

Why is this allowed? Is this due to the cast? When I do memcpy(&a[0], (const void*)&b[0], 3*sizeof(int)); compiler promptly generates the following warning:

cpy.c: In function ‘main’:
cpy.c:9:3: warning: passing argument 1 of ‘memcpy’ discards ‘const’ qualifier from pointer target type [enabled by default]
/usr/include/string.h:44:14: note: expected ‘void * __restrict__’ but argument is of type ‘const int *’
mmirzadeh
  • 6,893
  • 8
  • 36
  • 47

3 Answers3

6

You told the compiler to disregard the initial declaration when you performed the cast. It listened. That doesn't mean that your program is correct however. Modifying what was originally declared to be const results in undefined behavior (for example, the compiler is free to store that data in read only memory).

C doesn't hold your hand. If you chose to do something dangerous then it will let you.

Ed S.
  • 122,712
  • 22
  • 185
  • 265
4

Casting to void* removes the association with an int - by throwing away the type, you throw away the type decorators, such as const

Edit

As from discussion below, I want to make clear, that the important part is not to what you cast (void* in the OQ), but the fact that you cast - this implies throwing away your original type and its decorators.

Eugen Rieck
  • 64,175
  • 10
  • 70
  • 92
  • 1
    I don't think this is correct, you could cast to `int*` and would get the same results. – Jesse Good Sep 06 '12 at 23:02
  • 3
    You want to shoot in your leg? - C won't prevent you. – johannes Sep 06 '12 at 23:02
  • +1 @Jesse - the reason the code stops generating a warning is because the `const` is gone, not because it was casted to `void *`. – Carl Norum Sep 06 '12 at 23:03
  • @JesseGood It still stands, that the cast throws away the **original** type and thus throws away the **original** decorators – Eugen Rieck Sep 06 '12 at 23:06
  • the voidness and the constness are unrelated. This shitty answer got votes because it was first, I guess. -1 from me. – Alan Curry Sep 06 '12 at 23:06
  • @AlanCurry: Wow, you seem a bit angry, perhaps you should avoid the internet. The answer is fine, he never said there was anything special about casting to `void*`, that just happens to be what the OP cast the variable to. It may be a bit confusing, but yeesh. – Ed S. Sep 06 '12 at 23:07
  • @AlanCurry Thanks for your constructive input, I really appreciate it. As I already made clear, the point is the **cast**, not the **target type**. – Eugen Rieck Sep 06 '12 at 23:08
  • @EugenRieck, @EdS: The answer says `by throwing away the type`, this is **incorrect**, the type has nothing to do with it. – Jesse Good Sep 06 '12 at 23:09
  • While I was writing an actual explanation of what this code is doing there was a flood of quickies, all incomplete or wrong... this happens a lot. It seems like people are playing for points that they get from getting their answers out in public first instead of trying to be thorough. If I point this out I'm the one who should "avoid the Internet"? – Alan Curry Sep 06 '12 at 23:11
  • @AlanCurry History has decided. I thoroughly thank your for `writing an actual explanation of what this code is doing` while I was hacking up an incorrect quickie playing for points. At least you don't have a self-confidence problem – Eugen Rieck Sep 06 '12 at 23:14
  • Even in the edited version, this answer is wrong. The fact that there's a cast does not automatically mean you are throwing away constness. – Alan Curry Sep 06 '12 at 23:16
  • History has decided. I thank you again for your constructive and well-tempered input, that has really taught me a lot. Pity though, that I learnd more about you than about C. This concludes my participation in this pointless debate. – Eugen Rieck Sep 06 '12 at 23:19
  • The original post already demonstrated knowledge of the difference between cast to `void *` and cast to `const void *`, which this answer still hasn't grasped. This answer doesn't explain why overwriting the `const` data didn't crash (my answer explained that) or how one might get a compiler warning for such dangerous code (my answer explained that too). And the grandiose description of 19 minutes of anonymous website voting as a Judgement of History in your favor really shows what your priorities are. – Alan Curry Sep 06 '12 at 23:24
3

Casts usually suppress warnings. There is a gcc option, -Wcast-qual that will warn you about casts that are losing a const or volatile qualifier.

The program ran successfully because the memory used to store the array wasn't actually readonly, because they were allocated on the stack. This is an implementation detail and technically your code could have crashed if the implementation was really strict.

Declare a and b as globals and there's a greater chance it will crash (still not a guarantee)

Alan Curry
  • 14,255
  • 3
  • 32
  • 33