how to correctly address -Wcast-qual - c

I have a variable k of type const char *, and a function in glib with the prototype
void g_hash_table_replace(GHashTable *hash_table,
gpointer key,
gpointer value);
gpointer is defined simply as
typedef void* gpointer;
I know that in this case it is, in fact, okay to pass in k as the key in g_hash_table_replace, however gcc gives me the error
service.c:49:3: warning: passing argument 2 of ‘g_hash_table_replace’ discards ‘const’ qualifier from pointer target type [enabled by default]
/usr/include/glib-2.0/glib/ghash.h:70:13: note: expected ‘gpointer’ but argument is of type ‘const char *’
this is with gcc 4.6.0. With 4.5.0 and earlier, a simple cast to (char *) sufficed to supress this warning, but gcc seems to have gotten 'smarter'. I've tried (char *)(void *)k, but it still knows that the variable was originally const. What is the best way to silence this warning without calling strdup(3) on k?

I just tried this with gcc 4.6.1.
#include <glib/ghash.h>
#include <stdio.h>
#include <unistd.h>
const char *k="Testing";
int main(int argc, char **argv)
{
int val = 1024;
GHashTable *hash_table=NULL;
g_hash_table_replace(hash_table,(gpointer) (intptr_t)k, &val);
return 0;
}
Without casts, the error is as you describe above. But if I cast the const char* to intptr_t first as shown above, the warning is suppressed. Can you confirm that you still experience the error with my code sample?

Related

GCC issues warning of incompatible pointer type

When I compile the program below with GCC 4.9.2 I get the following warning: passing argument 1 of ‘P’ from incompatible pointer type. However, I don't see anything wrong with the program. Any clues?
typedef int Row[10];
void P(const Row A[])
{
}
int main(void)
{
Row A[10];
P(A);
return 0;
}
Here is the complete output from GCC to stderr:
test.c: In function ‘main’:
test.c:12:4: warning: passing argument 1 of ‘P’ from incompatible pointer type
P(A);
^
test.c:3:6: note: expected ‘const int (*)[10]’ but argument is of type ‘int (*)[10]’
void P(const Row A[])
^
Edit: The program compiles cleanly with Clang 3.5.0 and the options -pedantic -std=c89 -Wall.
Get rid of the typedef and it should become a little bit clearer:
void P (const int A [][10])
{
}
int main(void)
{
int A[10][10];
P(A);
return 0;
}
The problem is that the array in the function parameter "decays" into a pointer of type const int(*) [10], which is a pointer to an array where the items are const.
This pointer type is not compatible with what you pass from main, because that array decays into an array pointer of type int(*)[10].
There is a rule of "pointer-to-type may be converted to qualified-pointer-to-type". Meaning for example int* may be converted to const int* but not the other way around. But that rule does not apply here.
Because the qualified version of "pointer-to-array" is "const-pointer-to-array", and not "pointer-to-const-array", which is what you have here.
Unfortunately this is a weakness in the C language: you cannot have const correctness while using array pointers. The only solution is a very ugly one:
P( (const int(*)[10]) A);
It might be better to skip const correctness completely for cases like this, in favour of readability.
Edit: In C11 you can do like this, which is more type safe but it still relies on the caller performing a cast:
#define const_array_cast(arr, n) _Generic(arr, int(*)[n] : (const int(*)[n])arr )
void P (const int A [][10])
{
}
int main(void)
{
int A[10][10];
P(const_array_cast(A,10));
return 0;
}

Call a c function with a const matrix argument using a const cast

I am trying to call a c function with a const matrix argument using a const cast, but can't find the syntax that stops the gcc compiler complaining. The code below compiles without complaining if all "const " casts are removed. The quesion is similar to C function const multidimensional-array argument strange warning but no fully satisfactory solution was offered there. In the following code, if the first call to g() works, then the second call to g() should also work, since it is syntactically identical. But it does not. The second version of g() is preferred, because it does not require knowing in advance the type of the matrix.
/* file t.c */
void f(const int a[2]) {/*empty*/}
void g(const int b[2][2]) {/*empty*/}
int main()
{
int a[2];
int b[2][2];
f((const int (*)) a); /* ok */
f((const typeof(&a[0])) a); /* ok */
g((const int (*)[2]) b); /* ok */
g((const typeof(&b[0])) b); /* compiler complains */
}
$ gcc -o t t.c
t.c: In function ‘main’:
t.c:13:2: warning: passing argument 1 of ‘g’ from incompatible pointer type [enabled by default]
g((const typeof(&b[0])) b); /* compiler complains */
^
t.c:3:10: note: expected ‘const int (*)[2]’ but argument is of type ‘int (*)[2]’
void g(const int b[2][2]) {/*empty*/}
Yes, this lack of possibility to call a function with const 2D arrays with a non-const argument is really a defect in the C specification.
To move around it remember that
void g(const int b[2][2]) {/*empty*/}
is rewritten as
void g(const int (*b)[2]) {/*empty*/}
so this shows you how you'd have to convert, to a const int (*)[2], that is a pointer to an array of 2 double.
g( (const int (*)[2])b );
The const in the declaration header means that the function cannot change the contents of the argument. It is an information to the caller(compiler) and programmer. So there is no reason to make a const typecast then calling the function. It is totally superfluous.

C warning: incompatible pointer types passing [duplicate]

This question already has answers here:
c pthread passing array of type int
(2 answers)
Closed 7 years ago.
I keep getting an error when trying to compile my code. The error is as follows :
warning: incompatible pointer types passing
'void *(threadData *)' to parameter of type 'void * (*)(void *)'
[-Wincompatible-pointer-types]
pthread_create(&threads[id], NULL, start,&data[id]);
I'm trying to pass a struct to the function, void * start(threadData* data), and this keeps throwing me off. Any ideas?
It's complaining about the thread function (bound to the third parameter of pthread_create), you can modify that to take a void * argument and then cast it back before doing anything with it:
void *start (void *voidData) {
threadData *data = voidData;
// rest of code here, using correctly typed data.
You may also opt to coerce the data pointer (fourth parameter) to the expected type:
(void*)(&(data[id]))
but I don't think that's necessary since a void * is supposed to be freely convertible to and from most other pointers.
You can see the problem in this small yet complete program:
#include <stdio.h>
#include <string.h>
#include <pthread.h>
struct sData { char text[100]; };
void *start (struct sData *data) {
printf ("[%s]\n", data->text);
}
int main (void) {
struct sData sd;
pthread_t tid;
int rc;
strcpy (sd.text, "paxdiablo");
rc = pthread_create (&tid, NULL, start, &sd);
pthread_join (tid, NULL);
return 0;
}
When compiling that, you see:
prog.c: In function 'main':
prog.c:20:2: warning: passing argument 3 of 'pthread_create' from
incompatible pointer type [enabled by default]
In file included from prog.c:3:0:
/usr/include/pthread.h:225:12: note: expected
'void * (*)(void *)' but argument is of type
'void * (*)(struct sData *)'
Keep in mind that it's just a warning, not an error but, if you want your code to compile cleanly, it's worth getting rid of. Making the changes mentioned at the top of this answer (bar the data parameter casting) gives you the following thread function:
void *start (void *voidData) {
struct sData *data = voidData;
printf ("[%s]\n", data->text);
}
This compiles without warnings, and runs just fine.

Converting string to long using strtol and pointers

My goal is to convert a string such as "A1234" to a long with value 1234. My first step was to just convert "1234" to a long, and that works as expected:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
char* test = "1234";
long val = strtol(test,NULL,10);
char output[20];
sprintf(output,"Value: %Ld",val);
printf("%s\r\n",output);
return 0;
}
Now I am having trouble with pointers and trying to ignore the A at the beginning of the string. I have tried char* test = "A1234"; long val = strtol(test[1],NULL,10); however that crashes the program.
How do I set this up properly to get it pointing to the correct spot?
You are almost right. You need to pass a pointer to strtol, though:
long val = strtol(&test[1], NULL, 10);
or
long val = strtol(test + 1, NULL, 10);
Turning on some compiler warning flags would have told you your problem. For example, from clang (even with no special flags added):
example.c:6:23: warning: incompatible integer to pointer conversion passing
'char' to parameter of type 'const char *'; take the address with &
[-Wint-conversion]
long val = strtol(test[1],NULL,10);
^~~~~~~
&
/usr/include/stdlib.h:181:26: note: passing argument to parameter here
long strtol(const char *, char **, int);
^
1 warning generated.
and from GCC:
example.c: In function ‘main’:
example.c:6: warning: passing argument 1 of ‘strtol’ makes pointer from integer
without a cast
Editorial note: I think you can see from these error messages why beginners are often well-advised to use clang rather than GCC.

ISO C Void * and Function Pointers

While following some tutorials and reading about function pointers I learned that evidently assigning a void pointer to a function pointer in ISO C is undefined, is there any way to resolve the warning I receive during compile time (e.g. a better way of coding it) or should I just ignore it?
Warning:
ISO C forbids assignment between function pointer and 'void *' [-pedantic]
Example Code:
void *(*funcPtr)();
funcPtr = GetPointer();
GetPointer is a function that returns a void pointer E.G.
void *GetPointer();
In tlpi-book I found this trick very interesting:
#include <dlfcn.h>
int
main(int argc, char *argv[])
{
...
void (*funcp)(void); /* Pointer to function with no arguments */
...
*(void **) (&funcp) = dlsym(libHandle, argv[2]);
}
No. The compiler is right, and you too: in C89 and C99, you can't convert between data pointers (which void * is) and function pointers, so the only way for resolving the warning is returning a function pointer from the function.
(Note, however, that in practice this works despite the warning, and even there's this inconsistency in the standard library - the dlsym() function is used for obtaining function pointers, but it returns void * - so essentially you can ignore the warning. It will work, although strictly speaking the behavior is undefined here.)
I encountered this problem using glib. Glib data structures, such as GSList usually have a field called void *data. I wanted to store functions in a list and got a bunch of errors similar to this:
warning: ISO C forbids passing argument 2 of ‘g_slist_append’ between function pointer and ‘void *’ [-pedantic]
This example generates a bunch of warnings using gcc -Wall -ansi -pedantic
typedef int (* func) (int);
int mult2(int x)
{
return x + x;
}
int main(int argc, char *argv[])
{
GSList *functions = NULL;
func f;
functions = g_slist_append(functions, mult2);
f = (func *) functions->data;
printf("%d\n", f(10));
return 0;
}
So I wrapped the function in a struct and all the warnings go away:
struct funcstruct {
int (* func) (int);
};
int mult2(int x)
{
return x + x;
}
int main(int argc, char *argv[])
{
GSList *functions = NULL;
struct funcstruct p;
p.func = mult2;
functions = g_slist_append(functions, &p);
p = * (struct funcstruct *) functions->data;
printf("%d\n", p.func(10));
return 0;
}
It's arguable that this is quite a bit of extra code to make a few warnings disappear, but I don't like my code to generate warnings. Also, the above are toy examples. In the real code I'm writing, it turns out to be quite useful to wrap the list of functions in a struct.
I'd be interested to hear if this is problematic or if there's a better way of doing it.

Resources