warning C4090: 'function' : different 'const' qualifiers - c

I am observing error "warning C4090: 'function' : different 'const' qualifiers " because of below line of code. Going through other similar questions on SO I understand (not 100 percent) it is because of
--> const char* EmployeeList[] and my declaration in qsort of EmployeeList
#define Elements(array) (sizeof(array)/sizeof((array)[0]))
const char *EmployeeList[] =
{
"Larry Page", "Sergy Brin", "Sundar Pichai", "Merrisa Mayer"
};
// called from main
SortEmployee(EmployeeList, Elements(EmployeeList));
int Compare(const void *elemA, const void *elemB)
{
...
}
void SortEmployee(const char *EmployeeList[], size_t EmployeeCount)
{
qsort(EmployeeList, EmployeeCount, sizeof(EmployeeList[0]), Compare);
}
However I am unable to resolve it- Any pointers how to do it for array of strings.

The problem is qsort does not declare its argument as const, while your code does. That means qsort may (in theory) change data, pointed by EmployeeList. So, the compiler reports this error.
Here is the official example: https://msdn.microsoft.com/en-us/library/k77bkb8d.aspx
How ever, here is a simple version to demonstrate my idea:
void foo(char* a) {
*a = '1'; // I got pointer to char, and changed this char!
}
int main() {
const char *a = "A"; // I have "CONSTANT POINTER": it points to CONSTANT memory, that CAN NOT be changed (by the way, string constants can't in many environments).
foo(a); // I pass it to my function, that will change it.
return 0;
}
Image your compiler stores a in read-only memory (It can, because we told it "this is a pointer to READ ONLY data"). You then modify it (in main function). Something bad may happen. So, the compiler warns you "hey, you pass a pointer to constant data to some function, that does not know that this data is constant and may change it"

Related

Assigning value to the array of function pointers

I am trying to have an array of arrays of function pointers, but cannot assign to it, only statically initialize it:
#define N_INPUTS 2
#define N_STATES 2
void one()
{
//do stuff
}
void two()
{
//do stuff
}
//etc.
typedef void (*action_map[N_INPUTS])();
action_map my_action_maps[N_STATES];
//this would work:
//action_map am1 = {one, two};
//action_map am2 = {two, one};
//action_map my_action_maps[N_STATES] = { am1, am2 };
void init()
{
action_map am1;
am1[0] = one;
am1[1] = two;
my_action_maps[0] = am1; //error "expression must be a modifiable lvalue"
//however this works:
my_action_maps[0][0] = one;
my_action_maps[0][1] = two;
}
//the idea is to then handle input depending on a state with
//my_action_maps[state][input]();
I am not sure why is this happening, my_action_maps is just an array of pointers to function pointers, isn't it? Why it can initialized with initializer but then it is not modifiable?
This isn't really about function pointers, they are just making it harder to see the issue.
The type action_map is an array of function pointers. am1 and my_action_maps[0] are both of that type. But in C, you cannot assign an array to another array. It's the same issue as this:
int a[3] = {1,2,3};
int b[3] = {4,5,6};
a = b; // error
Current versions of gcc and clang both give a more useful message that explicitly says the problem is assigning to an array type. You might consider switching or upgrading your compiler.
You need to copy the elements one by one with a loop, or with memcpy. Thanks to array-pointer decay, you could do:
memcpy(my_action_maps[0], am1, sizeof(action_map));
Alternatively, you could wrap your action_map type in a struct, since you can assign structs to one another. But then it's a little more awkward to access the members.
typedef struct {
void (*actions[2])();
} action_map;
action_map my_action_maps[2];
void init(void) {
action_map am1;
am1.actions[0] = one;
am1.actions[1] = two;
// or: action_map am1 = { { one, two } };
// or: action_map am1 = { one, two };
my_action_maps[0] = am1; // ok
}
By the way, regarding your function and type declarations using empty parentheses, I suggest reading func() vs func(void) in C99 and Is it better to use C void arguments "void foo(void)" or not "void foo()"?. It may look like typedef void (*action_map[N_INPUTS])(); declares an array of pointers to functions taking no arguments, but it actually declares an array of pointers to functions taking unspecified arguments. This is supported mostly for compatibility with old versions of C and should generally not be used in new programs.
If you do am1[0](1,2,3); you will not get a compile error, and the compiler will happily attempt to pass three arguments to the function one that is not supposed to take any. This is undefined behavior. On some platforms, they might just be ignored, but you won't be alerted that you probably meant something else. On other platforms this may crash or worse. For instance, on a system using a calling convention where the called function is supposed to pop the stack (like the stdcall convention on Windows 32-bit compilers), calling a function with the wrong number of arguments will corrupt the stack.
So a better choice would be
typedef void (*action_map[N_INPUTS])(void);
Then action_map am1; am1[0](1,2,3); will cause a compiler error.
For consistency, I think it is also best to use void when defining a function with no parameters, e.g. void one(void) { ... }.

C - struct with a function pointer, how to fix "variable number of arguments" warning?

I'm trying to get rid of warning: assignment from incompatible pointer type [-Wincompatible-pointer-types] while adding func2 in this simplified example of dealing with a huge open source C library - which has a lot of functions like func1 and defines like str1.func = func1;. Is it possible to fix this warning without modifying func1 or writing something specific for each function / its' defines?
This code at OnlineGDB - https://onlinegdb.com/ry5rNlvDG , click "Fork this" to modify
#include <stdio.h>
void func1(int a) { // please don't change
printf("%i\n", a);
}
void func2(int a, char c) {
printf("%i - %c\n", a, c);
}
struct bigstruct {
// void (*func) (int a); // old way
void (*func) (int a, char c); // ??? - some magic needed
};
int main()
{
struct bigstruct str1, str2;
str1.func = func1; // please don't change
// ^^^ gives a warning: assignment from incompatible pointer type [-Wincompatible-pointer-types]
str2.func = func2;
error; // onlinegdb - error on purpose to see the warnings
}
UPDATE: eventually I figured out this is indeed impossible, but I got away from this situation just by adding a new field to the structure that has been passed around through this open source library from one function to another, and as result didn't have to add a new argument to the function. I'm giving top answer to "#Rarity" for his best attempt
I don't quite get your concern, if it's warning you're after, then -Wno-incompatible-pointer-types is probably ok.
Else, if you want to suppress warnings selectively, then change func declaration to:
struct bigstruct {
void (*func) ();
};
, then func will accept various function pointers. Type void ()() in C is "function which takes unknown number of unknown arguments (and returns nothing)", unlike void()(void) which is "a function that takes no arguments".
With your "please don't change"s it is not possible. However, you could make a cast:
str1.func = (void(*)(int, char))func1;
The function will be called with 2 parameters but it takes only one. On Intel and VC the second parameter will be ignored. (Parameters are pushed right-to-left onto the stack and func1 will only access the first parameter and will be unaware of any other parameters higher on the stack). This could be different on other architectures.

Why does passing arrays of non-const members to functions receiving them as const generate compiler warnings? [duplicate]

The const modifier in C++ before star means that using this pointer the value pointed at cannot be changed, while the pointer itself can be made to point something else. In the below
void justloadme(const int **ptr)
{
*ptr = new int[5];
}
int main()
{
int *ptr = NULL;
justloadme(&ptr);
}
justloadme function should not be allowed to edit the integer values (if any) pointed by the passed param, while it can edit the int* value (since the const is not after the first star), but still why do I get a compiler error in both GCC and VC++?
GCC: error: invalid conversion from int** to const int**
VC++: error C2664: 'justloadme' : cannot convert parameter 1 from 'int **' to 'const int **'. Conversion loses qualifiers
Why does it say that the conversion loses qualifiers? Isn't it gaining the const qualifier? Moreover, isn't it similar to strlen(const char*) where we pass a non-const char*
As most times, the compiler is right and intuition wrong. The problem is that if that particular assignment was allowed you could break const-correctness in your program:
const int constant = 10;
int *modifier = 0;
const int ** const_breaker = &modifier; // [*] this is equivalent to your code
*const_breaker = & constant; // no problem, const_breaker points to
// pointer to a constant integer, but...
// we are actually doing: modifer = &constant!!!
*modifier = 5; // ouch!! we are modifying a constant!!!
The line marked with [*] is the culprit for that violation, and is disallowed for that particular reason. The language allows adding const to the last level but not the first:
int * const * correct = &modifier; // ok, this does not break correctness of the code

C: Illegal conversion between pointer types: pointer to const unsigned char -> pointer to unsigned char

The following code is producing a warning:
const char * mystr = "\r\nHello";
void send_str(char * str);
void main(void){
send_str(mystr);
}
void send_str(char * str){
// send it
}
The error is:
Warning [359] C:\main.c; 5.15 illegal conversion between pointer types
pointer to const unsigned char -> pointer to unsigned char
How can I change the code to compile without warnings? The send_str() function also needs to be able to accept non-const strings.
(I am compiling for the PIC16F77 with the Hi-Tech-C compiler)
Thanks
You need to add a cast, since you're passing constant data to a function that says "I might change this":
send_str((char *) mystr); /* cast away the const */
Of course, if the function does decide to change the data that is in reality supposed to be constant (such as a string literal), you will get undefined behavior.
Perhaps I mis-understood you, though. If send_str() never needs to change its input, but might get called with data that is non-constant in the caller's context, then you should just make the argument const since that just say "I won't change this":
void send_str(const char *str);
This can safely be called with both constant and non-constant data:
char modifiable[32] = "hello";
const char *constant = "world";
send_str(modifiable); /* no warning */
send_str(constant); /* no warning */
change the following lines
void send_str(char * str){
// send it
}
TO
void send_str(const char * str){
// send it
}
your compiler is saying that the const char pointer your sending is being converted to char pointer. changing its value in the function send_str may lead to undefined behaviour.(Most of the cases calling and called function wont be written by the same person , someone else may use your code and call it looking at the prototype which is not right.)

Change string pointed by pointer

Many functions in c take pointer to constant strings/chars as parameters eg void foo(const char *ptr) . However I wish to change the string pointed by it (ptr).how to do it in c
You can just cast away the const:
void evil_function(const char *ptr)
{
char *modifiable = (char *) ptr;
*modifiable = 'f';
}
Note that this is dangerous, consider cases where the data being passed to the function really can't be changed. For instance, evil_function("bar"); might crash since the string literal is often placed in read-only memory.
Don't do it as it will cause your code to behave unpredictably. Basically the string pointed by const char* may be stored in the read-only section of your program's data and if you try to write something there, bad things will happen. Remember that foo can be called as foo("Test"), here you have not allocated memory for "Test" yourself, you just have a pointer to memory which contains the string. This memory may be read-only.
You can copy it to another piece of memory, and modify it there.
If you cast it to non-const, and then modify, chances are good you'll just segfault.
void foo(const char *x);
char data[4] = "Hi!";
int sum = 0;
for (int k=0; k<strlen(data); k++) {
foo(data); /* foo first */
sum += data[k];
}
printf("%d\n", sum);
Because foo() does not change its argument, the compiler can change this code to
void foo(const char *x);
char data[4] = "Hi!";
int sum = 0;
for (int k=0; k<strlen(data); k++) {
sum += data[k]; /* sum first */
foo(data);
}
printf("%d\n", sum);
But, if foo() changes the values in the data array, the results will be different according to the order the compiler chose to code the loop!
In short: don't lie to your compiler
How to lie to the compiler
Cast the const away
void foo(const char *readonly) {
char *writable = (char *)readonly;
/* now lie to the compiler all you like */
}
by notation "const char *ptr" we are telling Compiler
that ptr contains should not be changed.
Just, we can't change it!
The whole reason the const is so to express that the underlying content is not to be modified by this function, so don't change it because that will most likely break some code which is relying on the constness. other then that you can always cast the constness away using either const_cast<char*> or by directly casting the pointer
If you do it like this:
void dont_do_this_at_home(const char *ptr)
{
char **steve-o_ptr = (char **) &ptr;
char *bam_margera = "viva la bam";
*steve-o_ptr = bam_margera;
}
Then the pointer that you send into the function will be changed despite being a const pointer, the other suggestions so far only let you change the contents of the string, not the pointer to the string.
And I agree with the others that you shouldn't, ever, "un-const" any parameter you get, since the callee may really depend on that there are no side-effects to the function regarding those parameters.
There is also this way to get rid of the warnings/errors
typedef struct {
union {
const void* the_const;
void* the_no_const;
} unconsting;
}unconst_t;
/* Here be dragons */
void* unconst_pointer(const void* ptr) {
unconst_t unconst.unconsting.the_const = ptr;
return unconst.unconsting.the_no_const;
}
As you see it is quite possible and popular to actually do this, but you have to know what you are doing or mysterious faults may appear.

Resources