calling function pointer without typedef

Started by
13 comments, last by Bacterius 9 years, 11 months ago

Once time ago I was using dynamic dll linking ,

Here you obtain a function pointer by name,

You should also typedef this pointer but I was

lazy (those typedefs can be complex ) so i tried

to call it without typedef, something like

FARPROC SomeImportedFunction = NULL;

int x = SomeImportedFunction(1,2,3);

Has it (this way of using it) a chance to work?

(I think this is dangerous becouse compiler here has to guess

how to pass arguments and this is not type checked in the case

of some omittions or misaligments, wrong arg sizes), but if doing carefully

has this a chance to work, how to do it?

previously i was even unawara I can do this, I mean this way you can

push any arguments configuration then call the pointer, I am not sure how this is working - does it asume SomeImportedFunction is cdecl or stdcall

or what?

(I am not really sure what FARPROC hides, used it becouse it was

simplest not need to define any function pointedr typedef just using some)

Advertisement

FARPROC is a typedef:

int (FAR WINAPI * FARPROC) ()

In C, an empty parameter list means "turn off all type checking and pass in whatever I supply". In C++ it means "This method takes no parameters". The C form just makes the assumption that the called function knows what state the stack is in in terms of values that are there. Its more a throwback to the sort of "portable assembler" philosophy of C.

Its not clever to do this though. Far better to cast to a pointer to function typedef that specifies the arguments so the compiler can check you are calling it correctly. If you stuff up, the function will trash all over the stack when it runs.

FARPROC is a typedef:

int (FAR WINAPI * FARPROC) ()

In C, an empty parameter list means "turn off all type checking and pass in whatever I supply". In C++ it means "This method takes no parameters". The C form just makes the assumption that the called function knows what state the stack is in in terms of values that are there. Its more a throwback to the sort of "portable assembler" philosophy of C.

Its not clever to do this though. Far better to cast to a pointer to function typedef that specifies the arguments so the compiler can check you are calling it correctly. If you stuff up, the function will trash all over the stack when it runs.

I do not understand (some weak english)

Does this mean that this

FARPROC SomeImportedFunction = NULL;

//... obtaint pointer here from dll

int x = SomeImportedFunction(1,2,3);

will work in c but not in c++ or what ? (I usually wrote a c cod e but compile with basic c++ mode, and it seemed 'partially

work' there probably i was passing some wrong size types,

not sure so some worked, some not)

ps

if f() means any arg cann be called , like f(1) , f(1,2,3,4)

how to use it - wrote a definition for this, if args are unknown, i do not understand

Yes, it will work in C but not C++.

In C, a function with no arguments of the form f() can be passed any arguments at all and the compiler just ignores them in terms of checking. To define a C function that takes no arguments, you have to use the form f(void).

In C++ this changed and f() means no arguments. Calling a FARPROC pointer with arguments won't compile on a C++ compiler.

This implies that you, the programmer, are responsible for ensuring that the arguments you pass match whatever the function expects. It also means the compiler can't check that you are passing the correct arguments.

So in the case of loading functions from DLLs, it is far more sensible to create a typedef of a function with the correct arguments. You then only have to get this right in one place, when you cast the return from GetProcAddress, rather than get it right every time you call the resultant function.

If you remove all the winapi crap from the typedef you see that the function pointer FARPROC is defined as:


typedef int (*FARPROC)();

So it is indeed a pointer to a function which takes an indeterminate number of arguments. You can pass in anything you want, the compiler will set up the caller's stack accordingly, and the function will "read" the arguments passed off the stack (this could range from "explodes if you pass the wrong arguments" to "looks at the stack pointer to work out how many arguments were passed, varargs style"). In C, a function which takes exactly zero arguments should normally be written as foo(void).

At least, that is the case in C. As Aardvajk said, C++ deprecates the unspecified argument syntax, so that foo() is effectively equivalent to foo(void), in other words, you will not be able to call the function through the function pointer (or otherwise) with any arguments specified, and your snippet should not work. If it does, it means your C++ compiler is operating in some "C compatibility mode", or that it is simply broken. So for C++ you would presumably need to rewrite the function declaration to explicitly indicate the arguments, or use varargs syntax, and you would probably want to write an idiomatic C++ wrapper on top of it using std::bind or whatever (I don't really know a lot of C++, just saying you would typically write more high level code for this stuff).

So, to answer your question in plain english:


FARPROC SomeImportedFunction = NULL;
//... obtaint pointer here from dll
int x = SomeImportedFunction(1,2,3);

will work in c but not in c++ or what ? (I usually wrote a c cod e but compile with basic c++ mode, and it seemed 'partially
work' there probably i was passing some wrong size types,
not sure so some worked, some not)

Yes, it will not work in C++. If it work on your compiler, then you're not compiling C++ but C or some hybrid thereof.


if f() means any arg cann be called , like f(1) , f(1,2,3,4)
how to use it - wrote a definition for this, if args are unknown, i do not understand

You as a programmer are supposed to know how to call it. The compiler doesn't know nor care whether the arguments are right or wrong if it's not given a function signature, it will push the arguments into registers/onto the stack following whatever calling convention is in use and will then call the function. If the function can read the arguments (= same calling convention and expected number/format of arguments) then it will work. If not, your program will probably segfault inside the function, or, for some calling conventions, corrupt the stack. This syntax was designed to be very, very close to assembly level, if you don't understand how function calls happen in assembly then you will probably not understand how these types of functions work and why they are relevant. And if you do a lot of C and especially a lot of low-level interop (which it seems you do, seeing your recent posts on static lib compatibility) it would definitely not hurt to take a look.

“If I understand the standard right it is legal and safe to do this but the resulting value could be anything.”

FARPROC is a typedef:

int (FAR WINAPI * FARPROC) ()

In C, an empty parameter list means "turn off all type checking and pass in whatever I supply". In C++ it means "This method takes no parameters". The C form just makes the assumption that the called function knows what state the stack is in in terms of values that are there. Its more a throwback to the sort of "portable assembler" philosophy of C.

Its not clever to do this though. Far better to cast to a pointer to function typedef that specifies the arguments so the compiler can check you are calling it correctly. If you stuff up, the function will trash all over the stack when it runs.

alright, tnx, i agrre typedef is far better (I got silent runtime errors indeed), still I am curious;

Some typedefs were hard to obtain as far as i weakly remember ... Does mayby anyone know - If you have a dll

and a header to it , it contains header declarations of functions

... - is there a process of turning this declarations into needed typedefs an easy task, like

int foo(); -> typedef int (*p_foo) ();

or there I can meet some pitfalls or obstacles I'm vaguelly afraid of?

So, to answer your question in plain english:

ok, i understand

Yes, it will not work in C++. If it work on your compiler, then you're not compiling C++ but C or some hybrid thereof.

could be i always use c in c++ compiling mode but this was

a small pice and maybe i overlooked to set cpp mode


"You as a programmer are supposed to know how to call it. The compiler doesn't know nor care whether the arguments are right or wrong if it's not given a function signature, it will push the arguments into registers/onto the stack following whatever calling convention is in use and will then call the function. If the function can read the arguments (= same calling convention and expected number/format of arguments) then it will work. If not, your program will probably segfault inside the function, or, for some calling conventions, corrupt the stack. This syntax was designed to be very, very close to assembly level, if you don't understand how function calls happen in assembly then you will probably not understand how these types of functions work and why they are relevant. And if you do a lot of C and especially a lot of low-level interop (which it seems you do, seeing your recent posts on static lib compatibility) it would definitely not hurt to take a look."

i meant if i declare

int f();

how can i use then to use it one time to call like f(1,2)

or other time to call it f(1,2,3)

I can call it any way i like but in definition there is no arguments so how do i then acces to this 1,2 or 1,2,3 values

Function typedefs look scary but they are easy enough. Just write it like a function, then put parentheses around the name and put a start in front of the name, then remove parameter names.

double name(int i, const std::string &s);

typedef double (*name)(int, const std::string&);


I can call it any way i like but in definition there is no arguments so how do i then acces to this 1,2 or 1,2,3 values

A function would need to do some kind of interogation of the stack to figure out what had been pushed onto the stack prior to the call. Its not possible to do this in standard C and is not a common activity these days.

In the bad old days of C, people were used to working in assembly where they would manage their own stacks, so it was probably far more common back then to mess about with the stack directly in C. There's never really a good reason for that sort of thing in 2014, outside of very niche areas like embedded systems.

Templates, function overloading and inlining in C++ have pretty much removed any need for varadic functions. In C you have the va_args and ellipses system if you really need to mess about.

Here's a real world example from Caveman 3.0....

first, the typedefs....

//#################################### TYPEDEFS #####################################################
 
 
 
typedef void functiontype1();
 
typedef void functiontype2(int);
 
//#################################### END TYPEDEFS #####################################################

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

This topic is closed to new replies.

Advertisement