I came across the following function signature and I wondered if this (the ellipsis, or "...") is some kind of polymorphism?
#include <fcntl.h>
int fcntl(int fd, int cmd, ... );
Thanks in advance.
It's a variable argument list.
That is a variadic function. See stdarg.h for more details.
The ... means that you can pass any number of arguments to this function, as other commenters have already mentioned. Since the optional arguments are not typed, the compiler cannot check the types and you can technically pass in any argument of any type.
So does this mean you can use this to implement some kind of polymorphic function? (I.e., a function that performs some operation based on the type of its arguments.)
No.
The reason you cannot do this, is because you cannot at runtime inspect the types of the arguments passed in. The function reading in the variable argument list is expected to already know the types of the optional arguments it is going to receive.
In case of a function that really is supposed to be able to take any number of arguments of any type (i.e., printf), the types of the arguments are passed in via the format string. This means that the caller has to specify the types it is going to pass in at every invocation, removing the benefit of polymorphic functions (that the caller doesn't have to know the types either).
Compare:
// Ideal invocation
x = multiply(number_a, number_b)
y = multiply(matrix_a, matrix_b)
// Standard C invocation
x = multiply_number(number_a, number_b)
y = multiply_matrix(matrix_a, matrix_b)
// Simulated "polymorphism" with varargs
x = multiply(T_NUMBER, number_a, number_b)
y = multiply(T_MATRIX, matrix_a, matrix_b)
You have to specify the type before the varargs function can do the right thing, so this gains you nothing.
No, that's the "ellipsis" you're seeing there, assuming you're referring to the ... part of the declaration.
Basically it says that this function takes an unknown number of arguments after the first two that are specified there.
The function has to be written in such a way that it knows what to expect, otherwise strange results will ensue.
For other functions that support this, look at the printf function and its variants.
Does C support polymorphism?
No, it doesn't.
However there are several libraries, such as Python C API, that implements a rough variant of polymorphism using structs and pointers. Beware that compiler cannot perform appropriate type checking in most cases.
The tecnhique is simple:
typedef struct {
char * (*to_string)();
} Type;
#define OBJ_HEADER Type *ob_type
typedef struct {
OBJ_HEADER;
} Object;
typedef struct {
OBJ_HEADER;
long ival;
} Integer;
typedef struct {
OBJ_HEADER;
char *name;
char *surname;
} Person;
Integer and Person get a Type object with appropriate function pointers (e.g. to functions like integer_to_string and person_to_string).
Now just declare a function accepting an Object *:
void print(Object *obj) {
printf("%s", obj->type->to_string());
}
now you can call this function with both an Integer and a Person:
Integer *i = make_int(10);
print((Object *) i);
Person *p = make_person("dfa");
print((Object *) p);
EDIT
alternatively you can declare i and p as Object *; of course make_int and make_person will allocate space for Integer and Person and do the appropriate cast:
Object *
make_integer(long i) {
Integer *ob = malloc(sizeof(Integer));
ob->ob_type = &integer_type;
ob->ival = i;
return (Object *) ob;
}
NB: I cannot compile these examples rigth now, please doublecheck them.
I came across the following function signature and I wondered if this (the ellipsis, or "...") is some kind of polymorphism?
yes, it is a primitive form of polymorphism. With only one function signature you are able to pass various structures. However the compiler cannot help you with detecting type errors.
Adding to what's been said: C supports polymorphism through other means. For example, take the standard library qsort function which sorts data of arbitrary type.
It is able to do so by means of untyped (void) pointers to the data. It also needs to know the size of the data to sort (provided via sizeof) and the logic that compares the objects' order. This is accomplished by passing a function pointer to the qsort function.
This is a prime example of runtime polymorphism.
There are other ways to implement object-oriented behaviour (in particular, virtual function calls) by managing the virtual function tables manually. This can be done by storing function pointers in structures and passing them around. Many APIs do so, e.g. the WinAPI, which even uses advanced aspects of object orientation, e.g. base class call dispatch (DefWindowProc, to simulate calling the virtual method of the base class).
I assume you are referring to the ellipsis (...)? If so this indicates that 0 or more parameters will follow. It is called varargs, defined in stdarg.h
http://msdn.microsoft.com/en-us/library/kb57fad8.aspx
printf uses this functionality. Without it you wouldn't be able to keep adding parameters to the end of the function.
C supports a crude form of Polymorphism. I.e. a type being able to appear and behave as another type. It works in a similar was as in C++ under the hood (relying on memory being aligned) but you have to help the compiler out by casting. E.g. you can define a struct:
typedef struct {
char forename[20];
char surname[20];
} Person;
And then another struct:
typedef struct {
char forename[20];
char surname[20];
float salary;
char managername[20];
} Employee;
Then
int main (int argc, int *argv)
{
Employee Ben;
setpersonname((Person *) &Ben);
}
void setpersonname(Person *person)
{
strcpy(person->forename,"Ben");
}
The above example shows Employee being used as a Person.
No, it is a function that is taking variable number of arguments.
That is not technically polymorphism. fcntl takes variable number of arguments & that is the reason for the ... similar to printf function.
C neither supports function overloading - which is a type of ad-hoc polymorphism based on compile-time types - nor multiple dispatch (ie overloading based on runtime types).
To simulate function overloading in C, you have to create multiple differently named functions. The functions' names often contain the type information, eg fputc() for characters and fputs() for strings.
Multiple dispatch can be implemented by using variadic macros. Again, it's the programmer's job to provide the type information, but this time via an extra argument, which will be evaluated at runtime - in contrast to the compile-time function name in case of the approach given above. The printf() family of functions might not be the best example for multiple dispatch, but I can't think of a better one right now.
Other approaches to multiple dispatch using pointers instead of variadic functions or wrapping values in structures to provide type annotations exist.
The printf declaration in the standard library is
int printf(const char*, ...);
Think about that.
You can write code that supports Polymorphic behavior in C, but the ... (ellipsis) is not going to be much help. That is for variable arguments to a function.
If you want polymorphic behavior you can use, unions and structures to construct a data structure that has a "type" section and variable fields depending on type. You can also include tables of function pointers in the structures. Poof! You've invented C++.
Yes C Do support the polymorphism
the Code which we write in the C++ using virtual to implement the polymorphism
if first converted to a C code by Compiler (one can find details here).
It's well known that virtual functionality in C++ is implemented using function pointers.
Related
Is it safe to cast these 2 functions to callback pointer type then call them without casting back?
typedef void (*callback)(int i, ...);
void foo() {
// something.
}
void foo2(int i, int j) {
// something.
}
int main(void)
{
callback c = (callback)&foo, c2 = (callback)&foo2;
(*c)(0); (*c2)(0,1);
return 0;
}
The cast itself is safe, but you must use the correct type when calling the function. This is what the C standard 6.3.2.3 says:
A pointer to a function of one type may be converted to a pointer to a function of another type and back again; the result shall compare equal to the original pointer. If a converted pointer is used to call a function whose type is not compatible with the referenced type, the behavior is undefined.
In your case void (*)(int i, ...) isn't compatible with either of the other functions, so this code is wildly undefined behavior. However, some compilers provide non-standard extensions for generic function pointer use with the non-prototype void foo() style. But that one in turn is obsolete C and shouldn't be used for that reason - always use void foo (void) in C and never empty parenthesis.
Is it safe to cast these 2 functions to callback pointer type then call them without casting back?
No. The types of the two functions are not compatible with type callback, in the language specification's sense of "compatible", therefore calling either of those functions via a pointer of type callback invokes undefined behavior. Overall, non-variadic function types are never compatible with variadic ones, and in practice, many implementations use different calling conventions for one type than for the other, such that there is no plausible reason even to hope that calling a function of one variety as if it were of the other variety would have the desired effect in any consistent way.
You have several alternatives, among them:
Use different callback types for different purposes, each appropriate to its intended callback interface. This way you can avoid casting the callback functions at all. This would be my recommendation. It achieves the best type safety, and you need somehow to keep track of what the actual callback type is anyway, so that you can call it correctly.
Use a union of function pointer types. Callback specifiers assign to the appropriate member of the union, and callback callers select the appropriate member.
typedef union {
int (*unary)(int i);
int (*binary)(int i, int j);
} callback;
// ...
callback cb1 = { .unary = foo };
callback cb2 = { .binary = foo2 };
cb1.unary(1);
cb2.binary(1, 2);
You might even use a tagged union -- one that additionally carries information about which member is used. That would be a bit more complicated to use, but it would give you a means to achieve additional type safety. One of the variations on this approach would be my fallback recommendation if you need a single data type with which multiple callback types can be conveyed.
Choose a single callback type that meets all your needs. One way to do that would be to give it a parameter of type void *, by which callback functions can accept any number and type of inputs by, for example, a pointer to a suitable structure type.
typedef int (*callback)(void *);
struct one_int { int i1; };
struct two_int { int i1, i2; };
int foo(void *args) {
struct one_int *one_int = args; // ...
}
int foo2(void *args) {
struct two_int *two_int = args; // ...
}
Choose any function type as callback. Cast to that type going in, and back to the original type for calls.
Specify the callback type without a prototype. In C, if a function declaration that is not part of a definition of that function does not specify a parameter type list then that means that no information is provided about the parameters (unlike in C++, where that means that the function has no parameters). That is compatible with functions requiring any specific number of arguments -- but not variadic ones -- provided that applying the default argument promotions to the parameter types yields compatible types. Type int is a fine parameter type in that regard. The main ones that would be a problem are integer types narrower than int, plus float.
typedef int (*callback)();
This would allow exactly the usage you describe for the particular function types in your example.
callback cb1 = foo;
callback cb2 = foo2;
(*cb1)(1); // or just cb1(1)
(*cb2)(1, 2); // or just cb2(1, 2)
Contrary to another answer's claim, support for this approach does not constitute an extension to any version of the C language specification published to date. Supporting it is a requirement for conformance with any of C89, C99, C11, and C17. However, it has been declared "obsolescent" in C17, which constitutes a warning that it may be removed from some future version of the language specification. I expect that it indeed will be removed, possibly as soon as the next version of the specification, though obsolescence does not guarantee that.
No, the pointer will still point to the 'old' function (without parameters) and if you call the function, you will put variables on the stack which will never be used.
More problematic will be, if you have a pointer to the function with parameters and cast it to the function without parameters. Then, parameters will be fetched from the stack which you never put there. It is pure chance which values the program will operate on.
Note: This is the most likely behavior, but compilers are not bound to implement it this way (due to undefined behavior).
I guess you know this, but the safer way to do this sort of thing (although it's somewhat of a nuisance) is with explicit casts:
(*(void (*)(int, int))c2)(0, 1);
Here we:
take the generic "callback" function pointer c2
cast it to the correct function pointer type void (*)(int, int)
call it with the correct arguments
More problematic is your first callback, c. You're trying to call it with one integer argument 0, but you defined foo as accepting 0 arguments. So a more correct callback to foo as defined would be
(*(void (*)(void))c)();
Or if foo was supposed to take one argument of type int, that would be
(*(void (*)(int))c)(0);
And although as I said, the extra casts here can be a nuisance, this exercise illustrates their benefit: I didn't notice the mismatch between foo's definition and your callback c, until the compiler warned me about it after I inserted what I thought were the correct casts.
Without the casts, as other answers have explained, the code is unlikely to work. In particular, the attempt to make the callback type "variadic" (that is, with the ... in the prototype) does not help, and may very well hurt. These days, the calling conventions for variadic functions tend to be different from those for ordinary functions (a distinction which the ANSI/ISO C Standard has made since the beginning, although this marked a departure from K&R C). So if the compiler thinks that c2 points to a function of type void (*)(int, ...), and you call it with (0, 2), the compiler may very well use a different calling convention (the "varargs" one), and it might not be compatible with the non-varargs foo2, which is actually of type void (*)(int, int).
The bottom line is that it is safe to cast (convert) between function pointer types, but you must do it "on both ends"; that is, you must convert back to the correct type before calling. And "the correct type" must match both the actual function being called, and the actual arguments being passed.
I'm currently reading a beginner book about embedded systems "Making embedded Systems - design patterns for great software". In the testing section they say its a good idea to have a terminal interface to your embedded system, with a set of commands you can call, to test certain things in your system.
The way they suggest implementing these commands is by having an array of c structures comprised of a function pointer and a const char *. Then initialise your command array with your command names and respective functions you want to be called by that command.
You have the user select type a string, that string then gets compared to the char * in your command array and if it matches a particular entry call the corresponding function in the structure.
Here's the example code.
typedef void(*functionPointerType)(void);
struct commandStruct
{
char const *name;
functionPointerType execute;
char const *help
};
const struct commandStruct commands[] = {
{"ver", &CmdVersion, "Display firmware version"},
{"flashTest" &CmdFlashTest, "Runs the flash unit test"}
};
I understand this fine. What I don't understand is the throw away comment afterwards which says, if one wanted to pass arguments to the functions having one would parse them from the command string and pass them to the function defined by the function pointer.
I was at first confused because I didn't think that C would allow me to assign a function which takes an argument to a function pointer that expects void, but I tried it and I can my it compiles and runs. The compiler does give me warnings though.
I guess my question is this: Is this a perfectly valid thing to do or is it a bit of a "hack"? Will certain compilers not allow me to do this?
Well, first of all, you're not assigning a function to a function pointer, but a pointer to a function to an object that holds a pointer to a function. And you don't need an & either, a function name decays to a pointer to a function almost everywhere:
const struct commandStruct commands[] = {
{"ver", (functionPointerType)CmdVersion, "Display firmware version"},
{"flashTest" (functionPointerType)CmdFlashTest, "Runs the flash unit test"}
};
This should silence the warnings, though some newer versions of GCC have gotten some really annoying warnings that will be enabled with -Wall that will complain about this perfectly valid construct.
Note that when you call the function via this pointer, you must cast it back to the original prototype, otherwise the behaviour will be undefined.
Therefore if you want to pass in arguments, you'd better change functionPointerType so that it matches the prototype of both CmdVersion and CmdFlashTest; as an added bonus you'd not need to have those explicit casts any more.
Two function types are not "compatible" with each other if their return types differ. If both are declared with prototypes, then they also are not compatible if they take different numbers of arguments or if any of the pairs of corresponding arguments fail to have compatible types.
It is allowed to convert between pointers to incompatible function types, and some compilers might even perform such conversions automatically, without a warning, though that would constitute an extension. But you elicit undefined behavior if you call a function via a pointer to a function type incompatible with the function's actual type, or if you pass arguments that (after argument promotions and conversions, as applicable), are not compatible with the function's declared parameter types.
Thus, your book's throwaway comment at best falls a bit short.
If you want to provide a terminal interface that allows commands to take arguments then there are a couple of different ways to approach it, but my first suggestion would be to emulate the signature expected for main() in a hosted environment. That is, declare the handler functions with this signature, instead:
typedef void(*functionPointerType)(int argc, char *argv[]);
There might be reason to assert varying kinds of constness on argv. That puts fairly minimal parsing requirements on the front end of the terminal interface, while giving all your handler functions a consistent signature that can accommodate arguments.
It is poor advice. Here's how it is done in practice.
Define your callback functions similar to main(), i.e. taking the number of strings, and the strings, as arguments: int callback(int argc, char *argv[]).
So, your command list could be e.g.
static const struct {
const char *name;
const char *help;
int (*func)(int argc, char *argv[]);
} firmware_cmd[] = {
{ "help", "help [ command ]", help_func },
{ "ver", "ver", display_version },
{ "flashtest", "flashtest", flash_text },
{ 0 }
};
In the firmware command parser/lexer, define some specific callback function return values:
enum {
FIRMWARE_CMD_OK = 0,
FIRMWARE_CMD_ARGS, /* Invalid arguments! */
FIRMWARE_CMD_HELP, /* Command help asked */
/* All others are error/failure codes */
};
Now, when the command parser/lexer calls the function, it outputs additional text depending on the return value:
FIRMWARE_CMD_OK: "OK"
FIRMWARE_CMD_ARGS: "Invalid arguments. Run 'help COMMAND' to see help, or 'help' to see full command list."
FIRMWARE_CMD_HELP: the ->help text.
All other return values: Error (returnvalue)
This should allow simple, but versatile firmware command functions, with additional detail (in the error number) if an error fails.
if one wanted to pass arguments to the functions [...] one would parse them from the command string and pass them to the function defined by the function pointer
This means you would change the function pointer type to one taking arguments, not you would assign a function of a different type to the pointer.
Eg.
typedef void (*functionType)(int argc, const char *argv[]);
I was at first confused because I didn't think that C would allow me to assign a function which takes an argument to a function pointer that expects void, but I tried it and I can my it compiles and runs. The compiler does give me warnings though.
If your program doesn't compile with -Wall -Werror (for GCC-style options, at least), it probably isn't correct.
Compiling with warnings just means the compiler kept going as best it could - C compilers generally lets you do things that aren't strictly legal, on the grounds that you might know better.
Is this a perfectly valid thing to do ... ?
No. It's a hack that could work correctly in certain - different - circumstances. Specifically, if you cast the function pointer back to the right type (matching the function prototype) before calling, it will probably work. This only makes sense if you somehow know (or record) what the correct type is.
The standard does not allow this, as the types are not compatible.
For a function to match the type of a function pointer, number and types of the arguments, as well as the return type, have to match. Otherwise, the function will not be called correctly and you invoke undefined behavior.
When you have a set of functions that can be called through a function pointer, all of those functions need to have the same signature. One way to do this is to have all such functions accept a single parameter of type void *, similarly to functions that start a thread. That way you can use a struct to contain all the arguments in question and pass its address to the function, then the function would cast the void * back to the expected type.
So I have two functions that does the same thing but on different type variables.
The first function fills up an array of integers when given an int arr[] argument.
The second function fills up a linked list with integers also when given a struct as an argument.
The struct for the linked list argument looks something like this
typedef struct {node_t *head;int size;}
list_t;
Now I have implemented a table of function pointers for the two functions as such:
typedef struct{
char *name; //name of the function
void (*fill)(int arr[]); //fill up the array
} alg_t;
alg_t algs[] = {
{"func1",fill_up_arr},
{"func2",fill_up_linkedList}
};
Notice that inside the struct that holds my pointers, the fill function pointer
takes int arr[] as an argument.
I only want one pointer of a function in that struct, is there a way I can use
typecasting so that other functions such as fill_up_linkedList require argument to be of type list_t instead of int arr[]?
//This is what I want my main to look like.
//I want func.fill to be called only once thus
//dynamically perform the operations for all functions inside the table of
//functions array
int arr = malloc(sizeof(int)algs.size);
for(int i = 0; i<algs.size;i++){
alg_t func = algs[i];
func.fill(arr);
}
It seems that the problem with this code would be when the loop would try and perform the fill_up_LinkedList function as it needs a different argument.
How can I use a typecast in this situation?
Thanks
The good news
C11 §6.3.2.3 Pointers ¶8 (under the general topic §6.3 Conversions) says:
A pointer to a function of one type may be converted to a pointer to a function of another
type and back again; the result shall compare equal to the original pointer. If a converted
pointer is used to call a function whose type is not compatible with the referenced type,
the behavior is undefined.
That means you can store any and all function pointers in a common function pointer type, for example typedef void (*GenericFunctionPointer)(void). What is crucial, though, is that you convert from that generic function pointer type back to the correct function pointer type before you invoke the function via the pointer (and that you provide the correct argument list, and that you handle the return type appropriately, though ignoring the return value, if any, is always an option).
The bad news
For two different function pointer types, each with one instance of the the function, the infrastructure needed to support this is probably more elaborate than the savings, if any. On the other hand, if you have two or more different function pointer types, and most if not all of the types have many representative functions ('many' meaning 'more than one', as in the computer engineer's counting: "zero, one, many"), then the infrastructure can pay off. One of the issues is marshalling the function arguments — how are the arguments made accessible so that the function can be called via the pointer with the correct arguments.
So, doing things this way is complex and verbose.
The stated requirement
In a comment, the OP Moi says:
I only want to put one function in the struct. My goal is to find a way to allow fillArray to allow the passing of different args.
I have major reservations about the use of an uncounted array as the argument list as shown in the question — void (*fill)(int arr[]) is shown. In my view, it should be void (*fill)(size_t n, int arr[n]), using the variable length array notation. You can omit the n in the subscript if you wish — void (*fill)(size_t n, int arr[]) — or even use void (*fill)(int arr[], size_t n), which is the more classic order for the arguments.
Putting this concern aside, if you want a single function to accept different arguments, one way to achieve that is with void * as the type, but you have to be aware of the problems — one of which is type safety. You'll also need to borrow ideas from the standard C functions qsort() and bsearch(). The argument list will include the pointer to the start of the array as a void *, the size of each element of the array, and the number of elements in the array. You may also need analogues to the comparator functions.
Internal to the single called function, though, you will probably end up with two code paths, so although you call a single function via the pointer, you end up doing the equivalent of implementing two functions. You could use an interface similar to qsort()'s so that the two functions have the same interface and different bodies, and you use two pointers in the alg_t array.
Summary
You probably can't achieve the stated requirement cleanly.
You will probably need two logically separate functions to handle the two separate interfaces, even if you smush all the code inside a single function.
Use a union:
typedef struct {
char *name; //name of the function
union {
void(*fillArray)(int arr[]); //fill up the array
void(*fillList)(YourListType list); //fill up the list
};
} alg_t;
alg_t a;
a.fillArray(...);
a.fillList(...);
Or:
typedef struct {
char *name; //name of the function
union {
void(*fillArray)(int arr[]); //fill up the array
void(*fillList)(YourListType list); //fill up the list
} functions;
} alg_t;
alg_t a;
a.functions.fillArray(...);
a.functions.fillList(...);
Since you only have 2 types, you can just use an enum and a macro
enum e_type {e_foo,e_bar};
#define do_foobar(e,...) (e)?bar(__VA_ARGS__):foo(__VA_ARGS__)
replace foo and bar with your function names
If you only have the problem with the function parameters and not with the return value, there's a trick related to incomplete type definitions. The trick consists in leaving empty the list of parameters in the pointer type declaration, as in:
typedef void (*callback_ptr)();
which is different from:
typedef void (*callback_ptr)(void);
in the first case, the compiler will not check the parameters passed to the function, as the pointer is a pointer to an incompletely defined function type, while the second explicitly says the function doesn't require parameters and will give you an error if you try to call it with them.
I am implementing simple library for lists in C, and I have a problem with writing find function.
I would like my function to accept any type of argument to find, both:
find(my_list, 3) and find(my_list, my_int_var_to_find).
I already have information what is type of list's elements.
For now I've found couple of ways dealing with this:
different function with suffix for different types: int findi(void* list, int i), int findd(void* list, double d) - but I don't like this approach, it seems like redundancy for me and an API is confusing.
using union:
typedef union {
int i;
double d;
char c;
...
} any_type;
but this way I force user to both know about any_type union, and to create it before invocation of find. I would like to avoid that.
using variadic function: int find(void* list, ...). I like this approach. However, I am concerned about no restrictions on number of arguments. User is free to write int x = find(list, 1, 2.0, 'c') although I don't know what it should mean.
I have seen also answer to this question: C : send different structures for one function argument but it's irrelevant, because I want to accept non-pointer arguments.
What is the proper way of handling this function?
You could instead try implementing your function similar to a generic function like bsearch, which can perform a binary search on an array of any data type:
void *bsearch(const void *key, const void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *))
Rather than hard-coding the different implementations for different data types inside your function, you instead pass a pointer to a function which will do the type-dependent operation, and only it knows the underlying implementation. In your case, that could be some sort of traversal/iteration function.
The other thing bsearch needs to know (apart from the obvious - search key and array length) is the size of each element in the array, so that it can calculate the address of each element in the array and pass it to the comparison function.
If you had a finite list of types that were to be operated on, there's nothing wrong with having a family of findX() functions. The above method requires a function for each data type to be passed to the bsearch function, however one of the main differences is that common functionality doesn't need to be repeated and the generic function can be used for any data type.
I wouldn't really say there's any proper way to do this, it's up to you and really depends on the problem you're trying to solve.
I am not sure whether answering my own question is polite, but I want your opinion.
I tried to solve this problem using va_list. Why so? Because this way I can write only one function. Please, mind that I know what type the argument should be. This way I can do this:
int find(void* list, ...) {
any_type object = {0};
int i = -1;
va_list args;
va_start(args, list);
switch(type_of_elem(list)) {
case INT: object.i = va_arg(args, int); break;
...
}
/* now &object is pointer to memory ready for comparision
* f.eg. using memcmp */
return i;
}
The advantage of this solution is that I can wrap presented switch-case and reuse it with other functions.
After researching a little bit more on my concern regarding no limit on number of arguments I realized that printf lacks this limit either. You can write printf("%d", 1, 2, 3).
But I tweaked my solution with additional macro:
#define find_(list, object) find((list), (object))
Which produces error message at compile time, saying that find_ macro expects 2 arguments not 3.
What do you think about it? Do you think this is better solution than previously suggested?
I am trying to do something like the following
enum types {None, Bool, Short, Char, Integer, Double, Long, Ptr};
int main(int argc, char ** args) {
enum types params[10] = {0};
void* triangle = dlopen("./foo.so", RTLD_LAZY);
void * fun = dlsym(triangle, ars[1]);
<<pseudo code>>
}
Where pseudo code is something like
fun = {}
for param in params:
if param == None:
fun += void
if param == Bool:
fun += Boolean
if param == Integer:
fun += int
...
returnVal = fun.pop()
funSignature = returnval + " " + funName + "(" + Riffle(fun, ",") + ")"
exec funSignature
Thank you
Actually, you can do nearly all you want. In C language (unlike C++, for example), the functions in shared objects are referenced merely by their names. So, to find--and, what is most important, to call--the proper function, you don't need its full signature. You only need its name! It's both an advantage and disadvantage --but that's the nature of a language you chose.
Let me demonstrate, how it works.
#include <dlfcn.h>
typedef void* (*arbitrary)();
// do not mix this with typedef void* (*arbitrary)(void); !!!
int main()
{
arbitrary my_function;
// Introduce already loaded functions to runtime linker's space
void* handle = dlopen(0,RTLD_NOW|RTLD_GLOBAL);
// Load the function to our pointer, which doesn't know how many arguments there sould be
*(void**)(&my_function) = dlsym(handle,"something");
// Call something via my_function
(void) my_function("I accept a string and an integer!\n",(int)(2*2));
return 0;
}
In fact, you can call any function that way. However, there's one drawback. You actually need to know the return type of your function in compile time. By default, if you omit void* in that typedef, int is assumed as return type--and, yes, it's a correct C code. The thing is that the compiler needs to know the size of the return type to operate the stack properly.
You can workaround it by tricks, for example, by pre-declaring several function types with different sizes of return types in advance and then selecting which one you actually are going to call. But the easier solution is to require functions in your plugin to return void* or int always; the actual result being returned via pointers given as arguments.
What you must ensure is that you always call the function with the exact number and types of arguments it's supposed to accept. Pay closer attention to difference between different integer types (your best option would be to explicitly cast arguments to them).
Several commenters reported that the code above is not guaranteed to work for variadic functions (such as printf).
What dlsym() returns is normally a function pointer - disguised as a void *. (If you ask it for the name of a global variable, it will return you a pointer to that global variable, too.)
You then invoke that function just as you might using any other pointer to function:
int (*fun)(int, char *) = (int (*)(int, char *))dlsym(triangle, "function");
(*fun)(1, "abc"); # Old school - pre-C89 standard, but explicit
fun(1, "abc"); # New school - C89/C99 standard, but implicit
I'm old school; I prefer the explicit notation so that the reader knows that 'fun' is a pointer to a function without needing to see its declaration. With the new school notation, you have to remember to look for a variable 'fun' before trying to find a function called 'fun()'.
Note that you cannot build the function call dynamically as you are doing - or, not in general. To do that requires a lot more work. You have to know ahead of time what the function pointer expects in the way of arguments and what it returns and how to interpret it all.
Systems that manage more dynamic function calls, such as Perl, have special rules about how functions are called and arguments are passed and do not call (arguably cannot call) functions with arbitrary signatures. They can only call functions with signatures that are known about in advance. One mechanism (not used by Perl) is to push the arguments onto a stack, and then call a function that knows how to collect values off the stack. But even if that called function manipulates those values and then calls an arbitrary other function, that called function provides the correct calling sequence for the arbitrary other function.
Reflection in C is hard - very hard. It is not undoable - but it requires infrastructure to support it and discipline to use it, and it can only call functions that support the infrastructure's rules.
The Proper Solution
Assuming you're writing the shared libraries; the best solution I've found to this problem is strictly defining and controlling what functions are dynamically linked by:
Setting all symbols hidden
for example clang -dynamiclib Person.c -fvisibility=hidden -o libPerson.dylib when compiling with clang
Then using __attribute__((visibility("default"))) and extern "C" to selectively unhide and include functions
Profit! You know what the function's signature is. You wrote it!
I found this in Apple's Dynamic Library Design Guidelines. These docs also include other solutions to the problem above was just my favorite.
The Answer to your Question
As stated in previous answers, C and C++ functions with extern "C" in their definition aren't mangled so the function's symbols simply don't include the full function signature. If you're compiling with C++ without extern "C" however functions are mangled so you could demangle them to get the full function's signature (with a tool like demangler.com or a c++ library). See here for more details on what mangling is.
Generally speaking it's best to use the first option if you're trying to import functions with dlopen.