[comp.lang.c] Functions pointers and stuff

rds95@leah.Albany.Edu (Robert Seals) (03/28/89)

I got a question. Suppose I know the name of a function, like so:

	char *f = "A_Function";

and I got a function of the same name like so:

	void A_Function(void) { /* stuff */ }

Is there some sneaky way to execute the function when all I know is
the name of it, i.e., a pointer to several letters which spell it's name.

What I do now is have a table of names and pointers to functions, and
I have a function returning pointer to function, that, given a character
pointer, looks up the name in the table, and returns the corresponding 
pointer, which I then execute. It works fine, but I just wondered if
there was something else...and if I'm just being dumb, well, I'm sure
you'll clue me in.

rob

djones@megatest.UUCP (Dave Jones) (03/28/89)

From article <1715@leah.Albany.Edu>, by rds95@leah.Albany.Edu (Robert Seals):
> Is there some sneaky way to execute the function when all I know is
> the name of it, i.e., a pointer to several letters which spell it's name.
> 

There's no portable way.  What system are you running?  What version
of C?

henry@utzoo.uucp (Henry Spencer) (03/28/89)

In article <1715@leah.Albany.Edu> rds95@leah.Albany.Edu (Robert Seals) writes:
>Is there some sneaky way to execute the function when all I know is
>the name of it, i.e., a pointer to several letters which spell it's name.

Not unless your compiler is willing to help.  Most aren't.  In general
the correspondence between name and code address (which is usually what's
needed to call the thing) is lost at compile time.  Most compilers put an
indication of it into the symbol table, but programs don't have any easy
way to get at that information for themselves.
-- 
Welcome to Mars!  Your         |     Henry Spencer at U of Toronto Zoology
passport and visa, comrade?    | uunet!attcan!utzoo!henry henry@zoo.toronto.edu

net@tub.UUCP (Oliver Laumann) (03/28/89)

In article <1715@leah.Albany.Edu> rds95@leah.Albany.Edu (Robert Seals) writes:
> I got a question. Suppose I know the name of a function, like so:
> 
> 	char *f = "A_Function";
> 
> and I got a function of the same name like so:
> 
> 	void A_Function(void) { /* stuff */ }
> 
> Is there some sneaky way to execute the function when all I know is
> the name of it, i.e., a pointer to several letters which spell it's name.

You can look up the name in the program's symbol table, cast the value of
the symbol to "pointer to function returning ...", and call it.
Of course, this requires that your program can determine it's file name,
that the file is readable, that it has a symbol table, that the function
has not been declared as "static", etc., but you get the idea.

--
    Oliver Laumann, Technical University of Berlin, Germany.
    ...!pyramid!tub!net   or   net@TUB.BITNET
    ...!mcvax!unido!tub!net

tony@oha.UUCP (Tony Olekshy) (03/28/89)

From article <1715@leah.Albany.Edu>, by rds95@leah.Albany.Edu (Robert Seals):
>
> Is there some sneaky way to execute the function when all I know is
> the name of it, i.e., a pointer to several letters which spell it's name.

And from article <3182@goofy.megatest.UUCP>, by djones@megatest.UUCP
(Dave Jones):
>
> There's no portable way.  What system are you running?  What version...

And from the SVID (quasi-portable, if you have SV or Xenix or ?):

----------------------------------------------------------------
#include <a.out.h>
#include <stdio.h>

struct nlist nameinfo[] = { {"_f_name"}, {""} };

main()
{
    if (nlist(*argv, nameinfo) == -1) {

	fprintf(stderr, "Bad name list or function name.\n");
	exit (1);
	}

    /* Should check nameinfo[0].n_type here, but eventually... */

    (*(int (*)())(nameinfo[0].n_value))();

    exit (0);
    }

f_name()
{
    printf("f_name called!\n");

    return (0);
    }
-------------------------------------------------------------

Note that this is pretty slow on some machines, so you will want to cache
the data somehow.  You can check the mod time on *argv to invalidate cache
entries.  On the 286 this requires xlist(), then shift segment, or offset,
cast to pointer to function returning int, and dereference.  Have fun.

Yours, etc., Tony Olekshy (...!alberta!oha!tony or tony@oha.UUCP).

crossgl@ingr.com (Gordon Cross) (03/29/89)

In article <1715@leah.Albany.Edu> rds95@leah.Albany.Edu (Robert Seals) writes:
}I got a question. Suppose I know the name of a function, like so:
}
}	char *f = "A_Function";
}
}and I got a function of the same name like so:
}
}	void A_Function(void) { /* stuff */ }
}
}Is there some sneaky way to execute the function when all I know is
}the name of it, i.e., a pointer to several letters which spell it's name.

One way is to read the symbol table from the executable file.  This requires
that you can obtain the name of the file in all cases (someone could rename
your program only to discover that doing so breaks it!!).  The /proc file
system (if you have one) provides an ioctl call to get an open file descriptor
for the file.  Even so, the "strip" command would then break your program...

Simply put, there really is no better way (that I know of anyway) than the
name/function-pointer table lookup you are doing now...
-- 

Gordon Cross             UUCP:      uunet!ingr!crossgl     "all opinions are
111 Westminister Way     INTERNET:  crossgl@ingr.com        mine and not those
Madison, AL 35758        MA BELL:   (205) 772-7842          of my employer."

henry@utzoo.uucp (Henry Spencer) (03/30/89)

In article <301@oha.UUCP> tony@oha.UUCP (Tony Olekshy) writes:
>And from the SVID (quasi-portable, if you have SV or Xenix or ?): ...
>    if (nlist(*argv, nameinfo) == -1) {

The problem here is the assumption that argv[0] is a full pathname for
the program.  In general it's not, and finding the binary is not a
trivial exercise.
-- 
Welcome to Mars!  Your         |     Henry Spencer at U of Toronto Zoology
passport and visa, comrade?    | uunet!attcan!utzoo!henry henry@zoo.toronto.edu

hascall@atanasoff.cs.iastate.edu (John Hascall) (03/30/89)

In article <3182@goofy.megatest.UUCP> djones@megatest.UUCP (Dave Jones) writes:
>From article <1715@leah.Albany.Edu>, by rds95@leah.Albany.Edu (Robert Seals):
>> Is there some sneaky way to execute the function when all I know is
>> the name of it, i.e., a pointer to several letters which spell it's name.
 

>There's no portable way.  What system are you running?  What version
>of C?


	  struct {
	      char   *f_name;
	      int    (*f_func)();        /* if memory serves */
	  } stuff[] = {
	      {"fubar", fubar},
	              /* etc ..... */
	      {"blarg", blarg},
          }

    Then just search stuff[?].f_name for the function you want, and
    then do:  *(stuff[index].f_func)( args... );

    (It works faster if it is sorted by name so you can use a binary search.)

John Hascall / "More or less, anyhow!"

mnc@m10ux.UUCP (Michael Condict) (03/31/89)

In article <3182@goofy.megatest.UUCP>, djones@megatest.UUCP (Dave Jones) writes:

> From article <1715@leah.Albany.Edu>, by rds95@leah.Albany.Edu (Robert Seals):
> > Is there some sneaky way to execute the function when all I know is
> > the name of it, i.e., a pointer to several letters which spell it's name.
> > 
> 
> There's no portable way.  What system are you running?  What version
> of C?

While all the caveats mentioned in previous articles apply, here is a version
that is portable between System V and BSD derived UNIX's, including Suns.  Note
the occurrences of exit(n) for each of the many different things that can go
wrong.  Also note that it makes no attempt to solve the problem of converting
argv[0] into an accessible file name.  It calls the function "Funky" by using
nm to look up the address of the function in the a.out file.  Unfortunately,
this requires one #ifdef BSD, which you should #define when compiling on
Berkeley-derived systems.  The reason is that the BSD nm command prints hex
address, while System V prints decimal.

----------------------------------------------------------------------------
#include <stdio.h>
#include <ctype.h>

void Funky (str) char *str; { printf("Funky: %s\n", str); }

main(argc, argv) int argc; char **argv; {
	char *cp, *fname = "Funky";
	static char addr_str[100], nm_cmd[200];
	long addr = 0;
	FILE *f;
	void (*func_p)();

	printf("Begin test.\n");
	if (!argv[0] || ! argv[0][0]) exit(1);

	/* A command that will print the function address in ASCII: */
	(void)sprintf(nm_cmd, "nm %s | egrep '(^|[^a-zA-Z_])_%s[^a-zA-Z_0-9]'", argv[0], fname);
	if ((f = popen(nm_cmd, "r")) == NULL) exit(2);
	if (!fgets(addr_str, 99, f)) exit(3);
	if (!addr_str[0]) exit(4);

	/* Find the address in the nm output line: */
	for (cp = addr_str; *cp && !isdigit(*cp); cp++) ;
	if (!isdigit(*cp)) exit(5);

#ifdef BSD
		/* Convert ASCII hex representation to binary: */
		(void)sscanf(cp, "%x", &addr);
#else
		addr = atoi(cp);
#endif
	if (!addr) exit(6);

	func_p = (void (*)())addr;
	printf("func_p = 0x%x = %d\n", func_p, func_p);
	(*func_p)("was called.");

	printf("End Test.\n");
	exit(0);
}
-- 
Michael Condict		{att|allegra}!m10ux!mnc
AT&T Bell Labs		(201)582-5911    MH 3B-416
Murray Hill, NJ

colburn@lhasa.SRC.Honeywell.COM (Mark H. Colburn) (04/11/89)

In article <1715@leah.Albany.Edu> rds95@leah.Albany.Edu (Robert Seals) writes:
>Is there some sneaky way to execute the function when all I know is
>the name of it, i.e., a pointer to several letters which spell it's name.

There is a portable way to do this, given that you know the domain of
functions which can be called, but it is rather unwieldy.  If the
function that you are calling is one of the functions in your program,
then you can build a jump table that contains the name of all of the
functions in your program, along with the function's address.

For example, you could do somthing like:

void *malloc();
int   main();
int   foo();

struct func_table {
    char *func_name;
    void *(*func_addr)();
} func_table = {
    { "malloc", malloc },
    { "main", main },
    { "foo", foo },
};


The disadvantage of doing this is that return values are not handled
nicely and all of your functions which go into the table must be
declared before the table is built.  This works best if all of the
functions return the same thing, such as an int, or void, or whatever.

Building the table can be kind of a pain as well, however, it could be
automated with a few scripts.

Providing that all of your return values are handled correctly, or you
have different tables for each type of return value, I see no reason
why this should not be portable.

I don't know if that is what you are looking for, but it might help...
Mark H. Colburn           MN65-2300		colburn@SRC.Honeywell.COM
Systems Administration and Support
Honeywell Systems & Research Center