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.
Related
I was working on consolidating a code base (moving a qsort compar function to a new header /library so that it could be shared without being copy/pasta) and noticed something strange in the process.
Here is a demonstrative listing:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
/** One record has three fields.
* Each field contains a NULL terminated string of length at most 7 characters. */
typedef char Record[3][8];
int main(void)
{
Record database[5] = {0};
strcpy(database[0][0], "ZING");
strcpy(database[0][1], "BOP");
strcpy(database[0][2], "POW");
strcpy(database[1][0], "FIDDLY");
strcpy(database[1][1], "ECHO");
strcpy(database[1][2], "ZOOOM");
strcpy(database[2][0], "AH");
strcpy(database[2][1], "AAAAA");
strcpy(database[2][2], "AH");
strcpy(database[3][0], "BO");
strcpy(database[3][1], "DELTA");
strcpy(database[3][2], "FO");
strcpy(database[4][0], "FRRING");
strcpy(database[4][1], "CRASH");
strcpy(database[4][2], "FOO");
//(gdb) ptype record_compare_field_1
//type = int (char (*)[8], char (*)[8])
int record_compare_field_1();
qsort(database, 5, sizeof(Record), record_compare_field_1);
for (int i = 0; i < 5; i++){
printf("%s\t%s\t%s\n", database[i][0], database[i][1], database[i][2]);
}
}
/* Compares Records at field one. */
int record_compare_field_1(Record rowA, Record rowB)
{
return strcmp(rowA[1], rowB[1]);
}
Compile and run:
$ gcc -Wall main.c
$ ./a.out
AH AAAAA AH
ZING BOP POW
FRRING CRASH FOO
BO DELTA FO
FIDDLY ECHO ZOOOM
It's surprising to me that:
The compiler has no warnings since the signature of the compar function passed to quick sort does not have the prescribed function signature int (*compar)(const void *, const void *). Even in gdb, when I run ptype record_compare_field_1, it looks like the signature does not contain const *void.
The output is somehow correct? (Sorted based on field one (zero-indexed) results in AAAAA, BOP, CRASH, DELTA, ECHO.
The questions are:
Why/how does this work? Is this an old-school way of doing this?
If I wanted to change the qsort compar function in use to use the proper signature, how would I do that (I been struggling trying to come up with the proper casts)?
Thank you!
The int record_compare_field_1(); declaration does not have a prototype. This is an obsolescent feature of the C17/C18 standard.
In the function call qsort(database, 5, sizeof(Record), record_compare_field_1);, the record_compare_field_1 argument has type int (*)() and qsort's compar parameter has type int (*)(const void *, const void *). This is allowed by this rule from C17 6.2.7:
— If only one type is a function type with a parameter type list (a function prototype), the composite type is a function prototype with the parameter type list.
The actual record_compare_field_1 function definition has the prototype int record_compare_field_1(Record, Record) where the Record type is defined by typedef char Record[3][8]. Since array parameters are adjusted to pointers, this is the same as the prototype int record_compare_field_1(char (*)[8], char (*)[8]).
qsort will call the passed in record_compare_field_1 function with the wrong prototype, leading to undefined behavior. Most C implementations use the same representation for all object pointer types, so it lets you get away with it.
To do it properly, the record_compare_field_1 function could be defined like this:
int record_compare_field_1(const void *a, const void *b)
{
const Record *p_rowA = a;
const Record *p_rowB = b;
return strcmp((*p_rowA)[1], (*p_rowB)[1]);
}
I want to implement a stack using structures in C. Unfortunately, printf throws a segmentation fault. Perhaps there is a problem with dynamic allocation. Does anyone know how to solve it?
I have been facing this issue for the last two days. Your help will be very helpful for my study.
Here is my code
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define SIZE 256
typedef int (*pf)();
typedef struct _stack{
int arr[SIZE];
int top;
pf push, pop, peek, isEmpty, size, clear, print;
} stack;
void *nstack(){
stack *pstack = (stack *)malloc(sizeof(stack));
void push(int data) {
if(pstack->top < SIZE-1) pstack->arr[++pstack->top]=data;
}
int pop() {
return (pstack->top >= 0)?pstack->arr[pstack->top--]:0;
}
int peek(){
return (pstack->top >= 0)?pstack->arr[pstack->top]:0;
}
bool isEmpty(){
return (pstack->top >= 0)?false:true;
}
int size(){
return pstack->top+1;
}
void clear(){
pstack->top = -1;
}
void print(){
if(!isEmpty()){
for(int i = 0; i <= pstack->top; i++) printf("%d", pstack->arr[i]);
printf("\n");
}
}
pstack->push=push;
pstack->pop=pop;
pstack->peek=peek;
pstack->isEmpty=isEmpty;
pstack->size=size;
pstack->clear=clear;
pstack->print=print;
pstack->top=-1;
return pstack;
}
void dstack(stack *pstack){
free(pstack);
}
void main() {
stack *A = nstack();
A->push(1);
A->push(4);
A->push(6);
printf("%d",A->pop());
printf("%d",A->pop());
dstack(A);
}
While the code compiles (with warning), it try to leverage GCC extensions for functions within functions. However, the internal functions must be called within a valid context - they try to access the local pstackof the nstack function - but it does not exists.
While this style work in many OO langauges (Java, and possibly C++), that support 'closures' or lambda, it does not work for C. Consider changing the interface for each of the function to take stack *, and change the calling sequence to pass it.
void push(stack *pstack, int data) {
if(pstack->top < SIZE-1) pstack->arr[++pstack->top]=data;
}
main() {
...
A->push(A, 1) ;
...
printf("%d", A->pop(A) ;
}
Really, you should edit your question and provide the exact errors but I've decided to do some of the legwork for you since you're probably pretty new to this.
So first thing I did was compile your code here with -Wall and look what I get:
SO_stack.c: In function ‘nstack’:
SO_stack.c:49:17: warning: assignment from incompatible pointer type [-Wincompatible-pointer-types]
pstack->push=push;
^
SO_stack.c:52:20: warning: assignment from incompatible pointer type [-Wincompatible-pointer-types]
pstack->isEmpty=isEmpty;
^
SO_stack.c:54:18: warning: assignment from incompatible pointer type [-Wincompatible-pointer-types]
pstack->clear=clear;
^
SO_stack.c:55:18: warning: assignment from incompatible pointer type [-Wincompatible-pointer-types]
pstack->print=print;
^
SO_stack.c: At top level:
SO_stack.c:66:6: warning: return type of ‘main’ is not ‘int’ [-Wmain]
void main() {
Let's look at the first error on line 49: pstack->push=push;
You've defined push function prototype as: void push(int data) but pstack->push is of type pf which is defined as int (*pf)(); See the problem here? You're trying to pass an argument to a function pointer that is not properly defined to handle the argument AND the return type is different. This is totally wrong. Your push(int data) implementation declares a return type of void and a parameter of int yet your pointer to this function declares a return type of int and a parameter of void. This is the case with push, isEmpty, clear, and print. You're going to have to decide if all of these functions need to have the same prototype or if you need to create several different function pointer types to handle them, etc...
So that's the first problem.
Second problem is that as the warning says, you have a void main() prototype for your main function. You should return int from main and specify a return code to the caller of main (likely the OS)... Commonly, successful execution returns 0 and failure returns -1 but this is specific to the platform so you can instead return EXIT_SUCCESS on success and return EXIT_FAILURE upon failure from main. For this macros to be defined, you need to have #include <stdlib.h> present, which you do.
Next issue is that as a commenter wrote, you should learn to use a debugger such as GDB, LLDB, or Windows Debugger so that you can figure out exactly where the program crashes.
I've not re-written your program because it has so many issues that I don't think it would be constructive to do so in this iteration, however, provide an exact error next time, and use the debugger to see if the crash happens inside of the actual printf() code as you implied, or it happens because you supplied corrupt memory to the printf function. My guess is that it is the latter... Meaning, it is in fact probably your code which is flawed and supplying an invalid char * to printf which is either out of bounds, nonexistent, etc... This is precisely what you will use a debugger to find out, by placing a breakpoint before the trouble code and watching the memory to see what's going on.
You need to either remove int data.
Work on this some more, and you will probably find the rest of the issues yourself, if there are any. You should compile with flag -Wall and consider compiling with flag -Werror to clear this kind of stuff up yourself in the future.
In parseFunc() if I call loadFunc() by passing &tIpArray, it compiles fine when using C as the compile(in onlinegdb.com) but complains as below on a later version of C compiler(gcc-bin/4.9.4/gcc) at work.
Error at work is similar to what I see when I compile when using language as C++ in onlinegdb. Can someone tell me why the 4.9.4 gcc C compiler doesn't like the & and what is the right way to handle this?
/******************************************************************************
Welcome to GDB Online.
GDB online is an online compiler and debugger tool for C, C++, Python, PHP, Ruby,
C#, VB, Perl, Swift, Prolog, Javascript, Pascal, HTML, CSS, JS
Code, Compile, Run and Debug online from anywhere in world.
*******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
typedef struct _MyStruct
{
char string[72];
}MyStruct;
int loadFunc(MyStruct** ipData, int counter)
{
MyStruct **currentVal = ipData;
MyStruct *ipPtr = NULL;
printf("%p\n", currentVal);
for(int i=0; i<counter; i++)
{
ipPtr = currentVal[i];
printf("Line-%d - %s - %p\n", i+1, ipPtr->string, ipPtr);
}
}
int parseFunc()
{
MyStruct* tIPArray[3];
for(int i=0; i< 3; i++)
{
tIPArray[i] = 0;
tIPArray[i] = (MyStruct*) calloc(1, sizeof(MyStruct));
snprintf(tIPArray[i]->string, 72, "Test-String-%d", i+101);
}
for(int i=0; i<3; i++)
{
printf("Line-%d %p-%p- %s\n", i+1, &tIPArray[i], tIPArray[i], tIPArray[i]->string);
}
// call the load/ print loadFunc
loadFunc(&tIPArray, 3);
}
int main()
{
printf("Hello World\n");
parseFunc();
return 0;
}
Below is the error I get at work
error: passing argument 1 of 'loadFunc' from incompatible pointer type [-Werror]
loadFunc(&tIPArray, 3);
note: expected 'struct MyStruct **' but argument is of type 'struct MyStruct * (*)[(sizetype)((int)((short unsigned int)getMaxAddressObjects() / 4u))]'
int loadFunc(MyStruct **ipData, int counter)
Below error when building this in onlinegdb.com as C++ file
main.cpp: In function ‘int parseFunc()’:
main.cpp:49:38: error: cannot convert ‘MyStruct * (*)[3] {aka MyStruct * (*)[3]}’ to ‘MyStruct ** {aka MyStruct **}’ for argument ‘1’ to ‘int loadFunc(MyStruct **, int)’
loadFunc(&tIPArray, 3);
This declaration ...
MyStruct* tIPArray[3];
declares tIPArray as an array of 3 MyStruct *. Therefore, &tIPArray is a pointer to such an array, its type is MyStruct *(*)[3], just as the error message says. This is not the same type as MyStruct **, which is the expected type of the function argument.
You can instead pass an explicit pointer to the first element ...
loadFunc(&tIPArray[0], 3);
... but it would be more idiomatic to just omit the &, since ordinary conversion of array to pointer ("decay" of the array) produces a pointer of the correct type and value:
loadFunc(tIPArray, 3);
Perhaps it can be clearer if we use typedef MyStruct* StrPtr;. Then your example becomes:
void foo(StrPtr* bar);
StrPtr array[4];
First, let look at this call:
foo(array);
Array is of type StrPtr[4], not StrPtr*. Ideally this would call foo(StrPtr bar[4]) but there's no such function. The next best match is that arrays can decay to pointers to their elements = StrPtr* and luckily there's foo(StrPtr* bar) function so the call is valid.
Now, what is type of this expression?
&array;
Well, again array is of type StrPtr[4] so this must be a pointer to that type = StrPtr(*)[4]. Same "weird" syntax as for function pointers.
At last, take this call:
foo(&array);
We now know that this would like to call foo(StrPtr(*bar)[4]) and again there's no such function. So what can compiler do? &array is not an array, it's a pointer and pointers cannot decay to anything. Hmm, what now? Well, in C any pointer can be passed to another no matter the type. Dereferencing such pointer is another thing. So, this call is valid and calls foo(StrPtr* bar) as there's no other candidate. Success? No, any decent compiler should warn against this, even better turning those warnings into errors using -Wincompatible-pointer-types or even forbid all warnings with -Werror as you did.
So, the take away is that correct call is foo(array);.
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.
My problem is as follows:
I have a structure containing function pointers like this:
typedef void (CALLING_COVNENTION * functionType_t) (/*...*/);
typedef struct myFuncpointerStruc_s
{
/*...*/
functionType_t funcIdentifier;
/*...*/
}myFuncpointerStruc_t;
Now I want to assign a functionpointer of exactly that type to it.
But sadly dlsym() is returning a void * instead of something like function_poitner_type
So my first try:
functionscope ()
{
myFuncpointerStruc_t structIdentifier;
structIdentifier.funcIdentifier= dlsym (hAndle, "calledName");
}
ended in the warning:
WARNING: ISO C forbids assignment between function pointer and 'void *'
Ok, that confused me... gcc was never talking that harsh to me.
But OK lets get tricky I thought there will probably be any backdoor to keep it standard conform. So I tried this:
functionscope ()
{
myFuncpointerStruc_t structIdentifier;
*(void **) &structIdentifier.funcIdentifier = dlsym (hAndle, "calledName");
}
Hm.... obviously...
warning: dereferencing type-punned pointer will break strict aliasing rules
As I don't know what happens dlsym() internally I can't know I will break, as I get returned a real void * that aliases my function, or something quite different, can I?
So I cant know, will the use of this function pointer now break strict-aliasing rules or won't it?
But anyway: For my company it is law to use the compilerflag -fstrict-aliasing.
So this is also not a possible solution for me, even if it would be conform.
So I tried it by going on.
My next idea was: what about to parse a char * version of dlsym() into memcopy?
The result:
functionscope ()
{
myFuncpointerStruc_t structIdentifier;
unsigned char *localTestPtr = ((unsigned char *) dlsym (hAndle, "calledName");
memcpy (g_interfaceSvCheck.pfnPFD_SVCHK_GET_VERSION, localTestPtr, sizeof (localTestPtr));
}
The warning I'm getting now is pretty specific again:
warning: ISO C forbids passing argument 1 of ´memcpy´ between function pointer and ´void *´
So my next idea was kind of "lets go back to the bytes" maybe there I will get a way it will be working on.
(But slowly I'm running out of ideas...)
So I did:
functionscope ()
{
size_t testIndex;
myFuncpointerStruc_t structIdentifier;
unsigned char *localTestPtr = ((unsigned char *) dlsym (hAndle, "calledName");
for (testIndex = 0; testIndex < sizeof (localTestPtr); testIndex++)
{
((unsigned char *)(structIdentifier.funcIdentifier))[testIndex] = ((unsigned char *)&localTestPtr)[testIndex];
}
}
This ended in a quiet different warning:
WARNING: ISO C forbids conversion of function pointer to object pointer type
So finally my freakiest try was:
functionscope ()
{
size_t testIndex;
myFuncpointerStruc_t structIdentifier;
unsigned char *localTestPtr = ((unsigned char *) dlsym (hAndle, "calledName");
unsigned char * FakeFunctionPointer;
FakeFunctionPointer =
(((unsigned char *)structIdentifier) + offsetof (myFuncpointerStruc_t , funcIdentifier));
for (testIndex = 0; testIndex < sizeof (localTestPtr); testIndex++)
{
FakeFunctionPointer[testIndex] = ((unsigned char *)&localTestPtr)[testIndex];
}
}
And even here the problem is, that offsetoff's second parameter can't get converted to void * as it is a function pointer.
I'm stucked and don't know how to get further, could anyone help me please finding a solution?
I just have these warnings by using gcc 4.2 not with clang.
The targeted C version is -std=c99 to avoid is -std=POSIX and -std=gnu99
But this gcc warnings don't sound outdated to me.
I'm working currently on FreeBSD and I have really no idea left how to solve this.
This is kind of tricky:
#define CALLING_CONVENTION
typedef void (CALLING_CONVENTION * functionType_t) (/*...*/);
typedef struct myFuncpointerStruc_s
{
/*...*/
functionType_t funcIdentifier;
/*...*/
} myFuncpointerStruc_t;
int main()
{
myFuncpointerStruc_t structIdentifier = {0};
{
functionType_t * pfuncIdentifier = &structIdentifier.funcIdentifier;
*(void **) (pfuncIdentifier) = dlsym(handle, "calledName");
}
...
}
The above solution just tricks to compiler. The does not work from -O1 on anymore ... :-(
As there indeed is no solution, the only solution is to calm down the compiler. And the GNU people showed insight on this and invented: __attribute__ ((__may_alias__))
Here we can use it as follows:
#define CALLING_CONVENTION
typedef void * __attribute__ ((__may_alias__)) pvoid_may_alias_t;
typedef void (CALLING_CONVENTION * functionType_t) (/*...*/);
typedef struct myFuncpointerStruc_s
{
/*...*/
functionType_t funcIdentifier;
/*...*/
} myFuncpointerStruc_t;
int main()
{
myFuncpointerStruc_t structIdentifier = {0};
*(pvoid_may_alias_t *) (&structIdentifier.funcIdentifier) = dlsym(handle, "calledName");
}
...
}
And btw: Where does ldsym() come from? I only know dlsym().
Use two type-casts:
func_type *funptr;
funptr= (func_type *)(intptr_t)dlsym();
Type-casting funptr will cause troubles if size of code-pointers and data-pointers aren't equal.