最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c - Why is it allowed for a const pointer to be passed as non-const argument of a function and get modified? - Stack Overflow

programmeradmin4浏览0评论

I am able to pass a const pointer as argument of a function that takes non-const pointer.

Furthermore, inside the function body, I was allowed to modify its value as well with only a warning:
(passing argument 1 of 'modifyValue' discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers])
from the compiler but no error.

#include <stdio.h>

void modifyValue(int *ptr) {
    *ptr = 10; // This modifies the value pointed to by ptr
}

int main() {
    const int value = 5;
    const int *constPtr = &value;

    // This doesn't cause a compilation error
    modifyValue(constPtr);
    printf("%d",*constPtr);
    return 0;
}

demo

Is this behavior consistent with C spec? I would have assumed one could not pass const value as non-const argument as it strips away the const-ness. What is the point of the const qualifier if you can pass it through a function and change the value all the same?

I am able to pass a const pointer as argument of a function that takes non-const pointer.

Furthermore, inside the function body, I was allowed to modify its value as well with only a warning:
(passing argument 1 of 'modifyValue' discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers])
from the compiler but no error.

#include <stdio.h>

void modifyValue(int *ptr) {
    *ptr = 10; // This modifies the value pointed to by ptr
}

int main() {
    const int value = 5;
    const int *constPtr = &value;

    // This doesn't cause a compilation error
    modifyValue(constPtr);
    printf("%d",*constPtr);
    return 0;
}

demo

Is this behavior consistent with C spec? I would have assumed one could not pass const value as non-const argument as it strips away the const-ness. What is the point of the const qualifier if you can pass it through a function and change the value all the same?

Share Improve this question edited Mar 17 at 11:03 Toby Speight 31.4k52 gold badges76 silver badges113 bronze badges asked Mar 17 at 4:05 nabiknabik 776 bronze badges 9
  • 2 It's not allowed. That's why you got a warning. – dbush Commented Mar 17 at 4:07
  • 1 @nabikm Post warnings levels enabled. – chux Commented Mar 17 at 4:17
  • 2 With clang or gcc, you can add the command line option: -Werror=discarded-qualifiers – robthebloke Commented Mar 17 at 4:52
  • 4 Or simply add -Werror as a compiler option by default along with -Wall -Wextra -pedantic -Wshadow. While you are learning, having full warnings enabled and treating all warnings as errors ensure you fix the warnings (and as a side-effect learn quite a bit of C from your compiler). It's quite a good teacher. – David C. Rankin Commented Mar 17 at 4:59
  • 1 Back in the Jurassic period, some brontosaurus thought it was a great idea to write to string literals: char* str = "hello world"; ... strcpy(&msg[6], "dino");. Then later in the Cretaceous period, a meteor in the form of ISO C90 hit. But some compilers like gcc still thought it was still more important to preserve code written by the long-since extinct brontosaurus than to block "const to not const" conversions. Which is also the reason that the C90 dinosaurs from the Cretaceous period insisted that string literals in C must be char[] and not const char[]. – Lundin Commented Mar 17 at 10:13
 |  Show 4 more comments

2 Answers 2

Reset to default 7

Because C gives you enough rope to shoot yourself in the foot ^ACM.

I think the warning errors are enough:

~ » clang main.c                                                                                                                                                                                                                                                            
main.c:12:17: warning: passing 'const int *' to parameter of type 'int *' discards qualifiers [-Wincompatible-pointer-types-discards-qualifiers]
   12 |     modifyValue(constPtr);
      |                 ^~~~~~~~
main.c:3:23: note: passing argument to parameter 'ptr' here
    3 | void modifyValue(int *ptr) {
      |                       ^
1 warning generated.

» gcc main.c
main.c: In function ‘main’:
main.c:12:17: warning: passing argument 1 of ‘modifyValue’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
   12 |     modifyValue(constPtr);
      |                 ^~~~~~~~
main.c:3:23: note: expected ‘int *’ but argument is of type ‘const int *’
    3 | void modifyValue(int *ptr) {
      |                  ~~~~~^~~

Try running with -Werror

~ » clang -Werror main.c                                                                                                                                                                                                                                                    
main.c:12:17: error: passing 'const int *' to parameter of type 'int *' discards qualifiers [-Werror,-Wincompatible-pointer-types-discards-qualifiers]
   12 |     modifyValue(constPtr);
      |                 ^~~~~~~~
main.c:3:23: note: passing argument to parameter 'ptr' here
    3 | void modifyValue(int *ptr) {
      |                       ^
1 error generated.

~ » gcc -Werror main.c                                                                                                                                                                                                                                                      
main.c: In function ‘main’:
main.c:12:17: error: passing argument 1 of ‘modifyValue’ discards ‘const’ qualifier from pointer target type [-Werror=discarded-qualifiers]
   12 |     modifyValue(constPtr);
      |                 ^~~~~~~~
main.c:3:23: note: expected ‘int *’ but argument is of type ‘const int *’
    3 | void modifyValue(int *ptr) {
      |                  ~~~~~^~~
cc1: all warnings being treated as errors

Is this behavior consistent with C spec?

Yes - the compiler gave you some sort of message, which is all that is required. What must a C compiler do when it finds an error?

There's a common misunderstanding among beginners that warnings mean "here's a little cosmetic trifle you can fix some rainy day". In this case it meant "here's a severe bug - your program isn't even valid C". But for whatever the reason the compiler chose to generate an executable anyway - what that executable does is anyone's guess since it is a "not C program".

That's why I recommend beginners to enable all warnings and also set -Werror -pedantic-errors in case of gcc-like compilers.


Specifically, the program contains a constraint violation against the rules of assignment:

C23 6.5.3.3 Function calls

The arguments are implicitly converted, as if by assignment, to the types of the corresponding parameters

So basically the call modifyValue(constPtr); is the same as int* ptr = constPtr;. We must therefore go and check the rules of assignment, C23 6.5.17.2, emphasis mine:

Constraints

the left operand has atomic, qualified, or unqualified pointer type, and (considering the type the left operand would have after lvalue conversion) both operands are pointers to qualified or unqualified versions of compatible types, and the type pointed to by the left operand has all the qualifiers of the type pointed to by the right operand;

"qualifier" meaning type qualifier such as const. The left operand in this case is the function parameter, int *ptr, and the right operand is the function argument, const int *. The left operand does not have the const qualifier of the right operand, so this is a "constraint violation" - text found underneath the headline "constraints" in the C standard was violated, meaning that the code is invalid C and the compiler must give some sort of diagnostic message.

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论