pointers to functions, with flexible types - c

I write a code with a connectivity list of a flexible type.
My database contains a list of nodes with data that might be a char* or a VERTEX* (struct defined by me). hence I defined the struct as with a field void*.
I also wish to have an operation which compares the strings in that field, so the list has a field defined:
DATA_EQ DataEqual
and defined a function which checks if the data of two nodes is equal:
typedef BOOL (*DATA_EQ) (void* pl, void* pr);
in order to define a DATA_EQ function for the list, in the case of string data, I created the following function in the .c file:
static BOOL stringDataEqual(char* pd1, char* pd2){
return ( strcmp(pd1, pd2) == 0 );
}
Finally, I want this function to be defined on my list, so I wrote:
pList->dataEqual = stringDataEqual;
but I guess the fact that I tried to specify the void* as char* is not good.
I haven't worked with pointers to functions in the past, so I might have done some silly mistakes...
I got the warning (after running gcc to complie):
warning: passing argument 1 of ‘ListCreate’ from incompatible pointer type [enabled by default]
I need my code to compile without any warnings, how do I solve/work around that?
Thanks ahead to anyone who helps,
Oded

Use casts to cast to and from void pointers. Your function becomes:
static BOOL stringDataEqual(void* pd1, void* pd2) {
return ( strcmp((char*)pd1, (char*)pd2) == 0 );
}
You can call this function by casting the parameters to void*.

Related

Warning for anonymous union assignment in C

I'm building a small demonstration of a stack in C. As C has no exceptions, I'm trying out the result pattern (similar to Result<> in Swift 5) to deal with errors in creation, push, and pop.
I've created a header file that includes an error enum:
typedef enum {
no_error,
illegal_stack_capacity,
out_of_memory,
stack_element_too_large,
stack_full,
stack_empty
} stack_error;
a struct for the stack itself (I am using a stack of strings for concreteness, because at this point I am simply experimenting:
typedef struct {
char** data; // array of strings, capacity set on create()
int capacity; // have to store this separately!
int top; // index of next slot to fill, also the size
} stack;
and now to capture errors, I thought I would build a little struct that has an error part and a success part. As I am experimenting, I tried to have the error part do double duty as both a discriminated union tag as well as capture the error. This may be a hack, but it leads to (what I think is maybe) an interesting question.
typedef struct {
stack_error error;
union {
stack* stack; // because create() returns a stack
char* value; // because pop() returns a string
};
} result;
For reference (and sorry for the clutter), I have these functions:
result create(int capacity);
int size(const stack* s);
bool is_empty(const stack* s);
bool is_full(const stack* s);
stack_error push(stack* s, char* item);
result pop(stack* s);
void destroy(stack** s);
Now the question is that every time I build a result object, the C compiler seems to always assume the anonymous union component of my result struct is supposed to be a stack*. When I write, in my create function
return (result){no_error, s};
the compiler is fine with it, but when I write this in my pop function:
return (result){no_error, popped_value};
the compiler gives me a warning:
boundedstack.c:57:31: warning: incompatible pointer types initializing
'stack *' with an expression of type 'char *'
[-Wincompatible-pointer-types]
return (result){no_error, popped_value};
^~~~~~~~~~~~
I know I can get around this by (1) making the union not be anonymous or (2) creating separate types for stack_result (for create) and string_result (for pop), and maybe I should do that, but I am intrigued by this warning was wondering if any C language experts would know if anything in the language dictates that kind of warning, or if the warning was simply a decision by the compiler implementers to say "hey well I am just going to assume the proper type for the union is the first one I see". The code works just fine, but it seems to me the compiler could have done a better job. Or could it have? Could the compiler have done a better job? Or would it be too expensive of a check in the compiler?
(I really don't want to suppress warnings, as that is bad practice. Am I wrong to have tried the anonymous union?)
One way to get around the error is to use designated initialization:
return (result){.error=no_error, .value=popped_value};

Using right pointer type, dont want to cast with void *

Question regarding using the correct pointer type in my below code. When I try to initialize struct member function without type casting to void *, I got “initialization from incompatible pointer type” warnings ?
problem solved by typecasting but I want to use right pointer type instead of casting to void*.
Code snippet:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef void (*set_id)(int id);
typedef void (*set_name)(char *name);
typedef struct prop {
set_id *cb_setting_id;
set_name *cb_setting_name;
}prop;
prop *setting_id(int id) {
printf("ID:%d\n", id);
}
prop *setting_name(char *in) {
char *name;
name = in;
printf("Name:%s\n", name);
}
//Here type casted to void *, if not I get wrong pointer initalization
//error
prop cb_prop = { .cb_setting_id=(void *)setting_id,
.cb_setting_name=(void *)setting_name };
int main() {
prop *cb_event;
cb_event = &cb_prop;
cb_event->cb_setting_id = (void*)setting_id(2);
cb_event->cb_setting_name = (void*)setting_name("/dev/ttyS1");
return 0;
}
Without type casting, Warning are:
struct_callback.c:25:33: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
prop cb_prop = { .cb_setting_id=setting_id,
^
struct_callback.c:25:33: note: (near initialization for ‘cb_prop.cb_setting_id’)
struct_callback.c:32:26: warning: assignment from incompatible pointer type [-Wincompatible-pointer-types]
cb_event->cb_setting_id = setting_id(2);
Check the definition of e.g. the set_id type alias, it is a pointer to a function taking an int argument and not returning anything. Then compare it with the setting_id function, which is a function that takes an int arguments and returns a pointer to prop. Those two types are not compatible. It's made even worse because the setting_id function is declared to return a pointer to prop but doesn't actually return anything.
And not only that, but the members in the structure are pointers to e.g. set_id which means that cb_setting_id is a pointer to a pointer to a function.
Later on you do
cb_event->cb_setting_id = (void*)setting_id(2);
This is wrong because it calls the setting_id function, and tries to assign the returned value to cb_event->cb_setting_id. But the setting_id function doesn't return anything.
The solution to the first problem is to make sure that both the set_id type and the function setting_id are equal.
The solution to the second problem is to not declare the members are pointers (since they already are), or by changing set_id to not be a pointer.
The solution to the third problem is to remove those lines, since the the first two solutions should solve the initial initialization of the cb_prop structure.
The types you're assigning to are incompatible.
The function setting_id is of type prop *(*)(int), but the cb_setting_id field is of type void (*)(int). Simiarly for setting_name.
You need to change the typedef to match the function. Also, you have one extra level of indirection in your struct definition than you need.
typedef struct prop prop;
typedef prop *(*set_id)(int);
typedef prop *(*set_name)(char *);
struct prop {
set_id cb_setting_id;
set_name cb_setting_name;
};
First of all your function pointer typedef does not match the actual functions, because you use different return types. But here you hide the pointer syntax behind a typedef:
typedef void (*set_id)(int id);
typedef void (*set_name)(char *name);
Therefore, these become pointer-to-function-pointer:
set_id *cb_setting_id;
set_name *cb_setting_name;
That's not what you want. Simply change the typedefs to:
typedef prop* set_id (int id);
typedef prop* set_name (char *in);
Please note that you are not allowed to cast a function pointer to/from a void*. Void pointers assume object pointers, not function pointers. So casting a function pointer to void* results in an invalid pointer conversion.

C: Why aren't &(void *) and void** compatible?

I'm receiving an incompatible pointer type error warning although my code functions properly. First of all, here's a simplified version of my code:
typedef struct {
int field1;
int field2;
} my_struct;
void some_function(void **data){
// do something with *data
}
int main(int argc, char *argv[]){
my_struct *ptr = malloc(sizeof(my_struct));
ptr->field1 = 5;
ptr->field2 = 17;
some_function(&ptr);
}
The my_struct type is one example, but I'm actually using multiple types, so some_func must accept void**, rather than my_struct**. Each time I call some_func in the manner above, I recieve the following warning, and yet my code functions properly.
warning: passing argument 1 of ‘my_func’ from incompatible pointer type
I'm unsure of why these types aren't compatible, and would like to remove the warning in some way. For answers, feel free to explain why this is happening and, if possible, how to remove the warning (cpp directive, maybe?). Thanks!
Use a void * parameter type.
void ** is not a generic pointer type. void * is.
void* means (effectively) "a pointer to an untyped region of memory".
void** means (effectively) "a pointer to a region of memory, which contains pointers to untyped regions of memory".
Notice how the block in the middle has a type -- an array of void*. You're passing in effectively an array of mystruct*, which is a different type. So your compiler warns you.
Similar issues occur in C++ when trying to convert Derived** to Base**; but it applies here in C as well. (void* operates like the "base class" of all pointer types) Consider a piece of code like this:
void does_things(void** outParameter)
{
*outParameter = malloc(42); // Looks fine; writing void* to void* :)
}
int main()
{
my_struct* x = /*...*/;
does_things(&myStruct); // Ut oh, tries to make x point to
// something that is *not* a my_struct
}

How do you pass a typedef struct to a function?

At the moment I'm trying
void avg(everything)
But that gives me the error:
error: subscripted value is neither array nor pointer
And when I got this error earlier today it was because I wasn't passing a 2D array to the function properly. So I figure this is the same but I can't find the correct format to pass it in.
This is my typedef:
typedef struct structure
{
char names[13][9];
int scores[13][4];
float average[13];
char letter[13];
} stuff;
And this is my typedef array:
stuff everything[13];
In the function signature, you need to specify the type, not the specific name of a variable you want to pass in. Further, if you want to pass an array, you need to pass a pointer (you should probably be passing structs by pointers anyway, otherwise a copy of the data will be made each time you call the function). Hence you function should look like:
void avg(stuff* s);
However, C arrays also have no concept of length. Hence, you should always pass in the length of the array to the function:
void avg(stuff* s, size_t len);
You'd then call this as follows:
avg(everything, 13);
Also, if the function doesn't modify the data in any way, you should signify this by specifying that the parameter is const:
void avg(const stuff* s, size_t len);
A type introduced with typedef is an alias that can be used for a real type.
For example:
typedef struct some_struct { ... } some_type_name;
Now you can use some_type_name instead of struct some_struct.
So when declaring a function which takes a structure of this "type" you use the type like any other type:
void some_function(some_type_name var) { ... }
In some_function as defined above, you can use var like a normal structure variable.
To define a function taking an array (or a pointer) to this type, that's equally simple:
void some_function(some_type_name *pointer) { ... }

function pointer in C, with or without *?

is there difference between with or without * for function pointer in C?
my function pointer declaration like this
typedef void (*DListVisitNode) (Node*, void*);
void DListTraverse( NodeList* , DListVisitNode , void*);
i have code like these
void print_index( Node* node, void* ctx)
{
printf("index:%d\n", node->index);
}
void* print_content( Node* node, void* ctx)
{
printf("content:%s\n", node->content);
}
void DListTraverse(NodeList* nodelist, DListVisitNode visit_func, void* ctx)
{
Node* cur_node = nodelist->headnode;
while( cur_node != NULL)
{
visit_func( cur_node, ctx );
cur_node = cur_node->nextnode;
}
}
DListTraverse( nodelist, print_content, NULL );
DListTraverse( nodelist, print_index, NULL );
both of DListTraverse works, but the one with * throws warning like this
warning: passing argument 2 of ‘DListTraverse’ from incompatible pointer type
i would simply delete the * afterward, but what's the difference between them?
print_content is defined as returning a void* i.e. a generic raw pointer.
print_index is defined as returning void i.e. without any results.
These are different signatures. Only print_index matches DListVisitNode.
My coding style is to define signature thru typedef like
typedef void signature_t (int);
Notice that no pointer is involved above. This names the signature of functions with one int argument and no results.
then, when needing pointers to such functions of above signature, use signature_t*
What is true is that the name of a function is like the name of an array; the language implicitly convert these to pointers. So DListTraverse(nodelist, print_content, NULL) is understood like DListTraverse(nodelist, &print_content, NULL)
You should enable all warnings on your compiler; with gcc that means giving -Wall -Wextra as program arguments to the compiler.
You've declared print_content as returning a void * (a pointer), which means it doesn't match DListVisitNode. However, as the function doesn't actually return anything (no return statement), you should be gatting another warning about that.
You may be confused about the difference between the following to typedefs:
typedef void (*DListVisitNode) (Node*, void*);
typedef void * (*DListVisitNode) (Node*, void*);
Or equivalently, between the following two types:
void (*) (Node *, void *)
void * (*) (Node *, void *)
The former is a pointer to a function returning void, the latter is a pointer to a function returning void *. Each of your print functions is an example of one such function.
Naturally, function pointers of different types are incompatible and not implicitly convertible, as surely this would make no sense: You can't just pretend that a function actually has a completely different signature and expect to be able to call it in any meaningful way. It would be like pretending that a bicycle is a car and then trying to refuel it at a gas station.
typedef void (*DListVisitNode) (Node*, void*);
Defines a pointer to an function as an type which takes two parameters Node * and void * and returns a void.
Once you use the above statement, DListVisitNode can be used as an type, the exact type is as mentioned above.
void* print_content( Node* node, void* ctx)
returns a void * and not a void.
C is a strongly typed language, the c standard mandates that any type violations must be reported by the compiler, hence there is a type mismatch and the compiler reports it to you. Basically, if your function doesn't return anything use the return type as void or if you intend to return a particular type then use that specific type as an return type.

Resources