Compiler claims pointer is const when it is not used - c

My compiler gives this warning:
inlinedata.h:9:6: note: expected ‘char *’ but argument is of type ‘const char *’
int inline_data_receive(char *data,int length);
I don't understand why it claims 'data' is a const pointer when it is not written as a const char*.

It's saying that the argument (the data that you are passing in) is const. It might be a string literal, for example. So instead of doing this:
ret = inline_data_receive("hello", len);
do this
char str[] = "hello";
ret = inline_data_receive(str, len);
You need to do it this way since the function is not guaranteeing that it won't modify the input string.

The compiler is complaining that you are passing a const char* value to a value that is labeled as char*. Essentially the following
const char* c = ...;
inline_data_receive(c, strlen(c));
The compiler is complaining that c is const char* but needs to be char* to line up with the argument data

Related

Why I can't pass an argument of type 'char* const *' to a function which expected 'const char* const*' as it's argument? [duplicate]

This question already has answers here:
Double pointer const-correctness warnings in C
(3 answers)
expected expected ‘const char **’ but argument is of type ‘char **’
(1 answer)
Closed 2 years ago.
I am writing a function using fork and execv to replace system() and popen() in a project.
I found that although execv won't change the content of the command array, it declare it's second argument as char * const argv[], which can actually change the content of char*. Thus I decide to declare my function like this:int execute_cmd(const char* const cmd[]) so that both the pointer to char is const and the content the const pointer point to is const(Sorry I know this state is confusing but I tried)
However, when I call it in this way:
void execute_cmd(const char* const cmd[])
{
for (int i = 0; cmd[i]; i++)
{
printf("%s ", cmd[i]);
}
}
int main()
{
char* const cmd[] = {"ls", "-al", 0};
execute_cmd(cmd);
return 0;
}
there is a complie error saying that:
test.c:21: warning: passing argument 1 of ‘execute_cmd’ from
incompatible pointer type
test.c:10: note: expected ‘const char * const*’ but argument is of
type ‘char * const*’
I wonder why this happen because IMO an formal argument with const can take an non-const variable as it's actual parameter, such as:
void printInt(const int);
//which can call like this
int a=10;
printInt(a);
And I think initialize a const variable with a non-const variable is very common, So why this function work but my execute_cmd() didn't? Did I miss something importent with the const?
I have search "char * const * and const char* const *" and "const formal argument with non-const actual parameter" such things but haven't get something very useful, I will also appreciate if anyone can give me an idea about the correct key-work to this question.
I am not a native English speaker so if there are some grammar problem please forgive me.
I wonder why this happen because IMO an formal argument with const can take an non-const variable as it's actual parameter
It is more like "a formal parameter with const can take an non-const variable as it's actual argument."
const char* const cmd_paramter[] is like an "array of const pointer to const char".
char* const cmd_argument[] is an "array of const pointer to char".
Notice the type of the array elements differ: const char * vs. char *.
Same problem with simpler code: "expected 'char *' but argument is of type 'const char *'"
void foo(char *bob);
const char *alice = "Alice";
// Bad, as `foo()` needs to be able to write `*bob`, yet alice point to `const` data.
foo(alice);
Further, cmd array elements should be of type const char * to prevent writing a string literal.
// char* const cmd[] = {"ls", "-al", 0};
const char* const cmd[] = {"ls", "-al", 0};

Warning in Function pointer as a argument to another function

Just tried function pointer as an argument. Following code executed properly but throwing some warning. Not able to understand the warring. Can have some help here.
#include<stdio.h>
#include<string.h>
int concat(char *str1, char *str2, char *(*cat_fun) (const char *, const char *))
{
char str;
if(cat_fun) {
printf("%s\n",cat_fun (str1,str2));
return 0;
} else {
return 1;
}
}
int main(void)
{
char str1[20] = "super ";
char str2[] = "computer";
concat(str1,str2,strcat);
return 0;
}
Compilation:
gcc tttt.c
tttt.c: In function ‘main’:
tttt.c:22:2: warning: passing argument 3 of ‘concat’ from incompatible pointer type [enabled by default]
concat(str1,str2,strcat);
^
tttt.c:4:5: note: expected ‘char * (*)(const char *, const char *)’ but argument is of type ‘char * (*)(char * __restrict__, const char * __restrict__)’
int concat(char *str1, char *str2, char *(*cat_fun) (const char *, const char *))
^
This is the declaration of strcat:
char *strcat(char *dest, const char *src);
The first parameter is not a const pointer, because the function is supposed to modify that buffer. But your function pointer accepts that first parameter as a pointer to a const buffer, which is a promise that the pointee will not be modified. Naturally, that's a semantic incompatibility.
Strictly speaking, the C type system doesn't allow implicitly converting strcat to the pointer type you specify. But compilers may accept it in the interest of backward compatibility to older C versions, and emit only a warning. Bumping the standard compliance level in your build can help turn it into an error (and as such, maybe prevent nasty bugs down the line).
The first argument is char*, not const char*.
See here:
https://www.tutorialspoint.com/c_standard_library/c_function_strcat.htm

expected expected ‘const char **’ but argument is of type ‘char **’

Here is the compile warning i have:
src/Debugger.c:219:52: warning: passing argument 2 of ‘Debugger_Command[i].Callback’ from incompatible pointer type
Debugger_Command[i].Callback(argc, argv);
^
src/Debugger.c:219:52: note: expected ‘const char **’ but argument is of type ‘char **’
Here is the relevant source code:
/* Definition */
typedef void (*Debugger_Callback_t)(int argc, char const * argv[]);
typedef struct tagDebugger_Command_t {
/* ... */
Debugger_Callback_t Callback; /**< Callback */
} Debugger_Command_t;
Debugger_Command_t const Debugger_Command[] = { /* ... */ }
/* Use of the callback where the warning occurred */
char *argv[DEBUGGER_ARG_COUNT];
Debugger_Command[i].Callback(argc, argv);
What is wrong with passing a non const variable as a const parameter ?
To my understanding, this is to make sure the string wont be modified inside the function. So why is the warning occuring ?
Compiler: gcc version 4.9.2 (GCC) on Windows/Cygwin
Because technically you may be breaking a promise by passing a non-const pointer into a const pointer parameter.
"It is dangerous to take away const-ness"
http://c-faq.com/ansi/constmismatch.html
Here is the content of the above link:
You can use a pointer-to-T (for any type T) where a pointer-to-const-T is expected. However, the rule (an explicit exception) which permits slight mismatches in qualified pointer types is not applied recursively, but only at the top level. (const char ** is pointer-to-pointer-to-const-char, and the exception therefore does not apply.)
The reason that you cannot assign a char ** value to a const char ** pointer is somewhat obscure. Given that the const qualifier exists at all, the compiler would like to help you keep your promises not to modify const values. That's why you can assign a char * to a const char *, but not the other way around: it's clearly safe to ``add'' const-ness to a simple pointer, but it would be dangerous to take it away. However, suppose you performed the following more complicated series of assignments:
const char c = 'x'; /* 1 */
char *p1; /* 2 */
const char **p2 = &p1; /* 3 */
*p2 = &c; /* 4 */
*p1 = 'X'; /* 5 */
In line 3, we assign a char ** to a const char **. (The compiler should complain.) In line 4, we assign a const char * to a const char *; this is clearly legal. In line 5, we modify what a char * points to--this is supposed to be legal. However, p1 ends up pointing to c, which is const. This came about in line 4, because *p2 was really p1. This was set up in line 3, which is an assignment of a form that is disallowed, and this is exactly why line 3 is disallowed.
Assigning a char ** to a const char ** (as in line 3, and in the original question) is not immediately dangerous. But it sets up a situation in which p2's promise--that the ultimately-pointed-to value won't be modified--cannot be kept.
(C++ has more complicated rules for assigning const-qualified pointers which let you make more kinds of assignments without incurring warnings, but still protect against inadvertent attempts to modify const values. C++ would still not allow assigning a char ** to a const char **, but it would let you get away with assigning a char ** to a const char * const *.)
In C, if you must assign or pass pointers which have qualifier mismatches at other than the first level of indirection, you must use explicit casts (e.g. (const char **) in this case), although as always, the need for such a cast may indicate a deeper problem which the cast doesn't really fix.

C arrays of arrays: why do I need to cast TO const here?

Why do I need to change the print_args call in this code to print_args(argc, (const char**)argv) to make it compile?
#include <stdio.h>
void print_args(int argc, const char *argv[]) {
for (int i = 0; i < argc; ++ i) {
puts(argv[i]);
}
}
int main(int argc, char *argv[]) {
print_args(argc, argv);
return 0;
}
When I compile it with gcc I get this error:
$ gcc -Werror -std=c99 -g const.c -o const
const.c: In function ‘main’:
const.c:10:2: error: passing argument 2 of ‘print_args’ from incompatible pointer type [-Werror]
const.c:3:6: note: expected ‘const char **’ but argument is of type ‘char **’
cc1: all warnings being treated as errors
(Note that this is just a simplified example code to illustrate the problem.)
The comp.lang.c FAQ has a question on this, summarizing:
The reason that you cannot assign a char ** value to a const char **
pointer is somewhat obscure. Given that the const qualifier exists at
all, the compiler would like to help you keep your promises not to
modify const values. That's why you can assign a char * to a const
char *, but not the other way around: it's clearly safe to "add"
const-ness to a simple pointer, but it would be dangerous to take it
away...In C, if you must assign or pass pointers which have qualifier
mismatches at other than the first level of indirection, you must use
explicit casts
Here's the example it gives, where line 3 should give a warning:
const char c = 'x'; /* 1 */
char *p1; /* 2 */
const char **p2 = &p1; /* 3 */
*p2 = &c; /* 4 */
*p1 = 'X'; /* 5 */
Lines 1 and 2 are obviously fine. On line 4, &c has type pointer to const char, and since char ** is type pointer to pointer to const char, then *p2 is also of type pointer to const char, so the statement is fine. Line 5 is also fine, because p1 is type pointer to char, so you can modify what it points to.
So if line 3 is OK, then you end up doing exactly what you expect const to prevent you from doing, modifying the char pointed to by a pointer to pointer to const char, so line 3 is not allowed, and you can't assign char ** to a const char ** without a cast.
Note that putting the cast in merely hides the problem, it doesn't fix it. Line 3 above would work if you added the cast, and you'd be able to indirectly modify an apparently const char. While it's not always true, this is a good example of where succumbing to an apparent need to cast in C is often just a mistake.
Note that in C++, you could declare your function parameter const char * const * argv and it would work without a cast, and prevent the indirect modification.

const char** parameter warning about char** argument

During compilation of a call to the following function:
char* process_array_of_strings(const char** strings);
GCC complains when a char** is passed as argument:
note: expected ‘const char **’ but argument is of type ‘char **’
While the function does not alter the characters (hence the const) it does duplicate the array of pointers in order to modify the character pointers themselves, so constant pointers are definitely undesirable here.
Compilation succeeds and the program appears to work. So how is the programmer supposed to handle this warning?
Make the conversion explicit with a cast and the compiler will be happy:
process_array_of_strings((const char**) foo);
In these cases you have to explicitly say that you know what you're doing.
This is why char ** is not automatically converted to const char ** in C++, and why the C compiler issues a warning while allowing it.
/* This function returns a pointer to a string through its output parameter: */
void get_some_string(const char ** p) {
/* I can do this because p is const char **, so the string won't be modified. */
*p = "unchangeable string in program core";
}
void f() {
char * str;
/* First, I'll call this function to obtain a pointer to a string: */
get_some_string(&str);
/* Now, modify the string: */
for (char * p = str; *p; p++)
*p = toupper(*p);
/* We have just overwritten a constant string in program core (or crashed). */
}
From your description of what process_array_of_strings() does, it could just as well take const char * const * because it modifies neither the pointers nor the characters (but duplicates the pointers elsewhere). In that case, the above scenario would not be possible, and compiler theoretically could allow you to convert char ** to const char * const * automatically without warnings, but that's not how the language is defined.
So the answer is obviously that you need a cast (explicit). I've written up this expanation so that you can fully understand why the warning appears, which is important when you decide to silence one.

Resources