[comp.lang.c] Can this be done

jfjr@mitre-bedford.arpa (07/01/87)

 I posted this sometime back but it appears to have been lost
so I am posting it again. If its redundant I have screwed up and
I apologize.

 Suppose I have defined a structure type with one of the components
a pointer to a function. For simplicity's sake the function takes
no parameters and returns void. Suppose further I declare, in
one module an array of such structures and in that same module
(compilation unit) I define(declare??) a function we'll call
"install" which takes a one of these function pointer structures
as a parameter, searches through the array for an empty spot
and copies the structure into it.

 Now, in another, separate module I have an instance of my
function pointer structure and the function (call it my_function)
it points to is also in this module. I make NO attempt to make 
this function visible outside the module. I make "install"
visible and in fact I call it to install this structure 
into the array described above. Can I loop through my array
and call the functions in it even though none are declared 
external anywhere? is this legal? possible but not legal??
done every day?? - how far can I push this?? Any comments
are welcome

                                         Jerry Freedman,Jr
                                         jfjr@mitre-bedford.arpa

gwyn@brl-smoke.ARPA (Doug Gwyn ) (07/02/87)

In article <8125@brl-adm.ARPA> jfjr@mitre-bedford.arpa writes:
>... Can I loop through my array and call the functions in it even
>though none are declared external anywhere?

It's not only legal, it's a good way to hide function names from
other modules.  A function need not be visible globally in order
to be called from other modules.  (The only need for global
visibility is to permit external linkages to be resolved by the
link editor; in your case there are no such linkages.)

I won't guarantee that all C implementations handle this
correctly, but it's an implementation bug if one doesn't.
(I don't know of any C implementations that can't handle this.)

dg@wrs.UUCP (David Goodenough) (07/06/87)

In article <8125@brl-adm.ARPA> jfjr@mitre-bedford.arpa writes:
>
>Now, in another, separate module I have an instance of my
>function pointer structure and the function (call it my_function)
>it points to is also in this module. I make NO attempt to make 
>this function visible outside the module. I make "install"
>visible and in fact I call it to install this structure 
>into the array described above. Can I loop through my array
>and call the functions in it even though none are declared 
>external anywhere? is this legal? possible but not legal??
>done every day?? - how far can I push this?? Any comments
>are welcome

Please find enclosed a quick shell archive that should help explain.

Note that the operative phrase in test2.c when I'm talking about my_func
is that because it's static it can't be referenced _BY_NAME_ outside
test2.c. There's nothing to stop me from using it's name inside test2.c
and passing the resultant pointer around (which is in fact what I'm
doing). _ALL_ that happens when you "static-ize" (? :->) an object is
that the assembler source doesn't have a .globl associated with the name
so the name doesn't make it into the list of names that can be used to
resolve external undefineds, hence if test1.c tried to refer to my_func
with lines of the type:

    extern int my_func();

and

    a = my_func();

you'd get an 'Undefined: _my_func' type of complaint from ld.
--- Cut Here --- Cut Here --- Cut Here --- Cut Here --- Cut Here ---
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the '#! /bin/sh' line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (NOT csh) to create the files:
#	A: test1.c
#	B: test2.c
#
if test -f test1.c
then
    echo shar: file test1.c already exists
else
    echo shar: extractng test1.c
    cat <<\##__EOF..test1.c__## >test1.c
#define NULL	0
#define NUM_STR	10

struct					/* this is the structure */
 {
    int _junk1;
    int (*_func)();			/* here is the function pointer */
    int _junk2;				/* the rest (_junk[12]) is filling */
 } list[NUM_STR];

main()
 {
    int i;

    for (i = 0; i < NUM_STR; i++)
      list[i]._func = NULL;		/* set all pointers to NULL */
    install();				/* install my_func */
    call_all();				/* now go call it */
 }

call_all()
 {
    int i;

    for (i = 0; i < NUM_STR; i++)	/* check each structure */
      if (list[i]._func)		/* anything here to call? */
	(*list[i]._func)();		/* yes - go do it */
 }
##__EOF..test1.c__##
if test 614 -eq `wc -c <test1.c`
then
    echo shar: test1.c extracted OK
else
    echo shar: Warning - test1.c extracted with wrong size
fi
fi
if test -f test2.c
then
    echo shar: file test2.c already exists
else
    echo shar: extractng test2.c
    cat <<\##__EOF..test2.c__## >test2.c
extern struct				/* this is the structure */
 {
    int _junk1;
    int (*_func)();			/* here is the function pointer */
    int _junk2;				/* the rest (_junk[12]) is filling */
 } list[];

static my_func()			/* the function we're trying to call
					 * note that it's static so it can't
					 * be referenced _BY_NAME_ outside
					 * this source module */
 {
    printf("Hello World!\n");		/* do something */
 }

install()
 {
    list[0]._func = my_func;		/* install my func into the array */
 }
##__EOF..test2.c__##
if test 498 -eq `wc -c <test2.c`
then
    echo shar: test2.c extracted OK
else
    echo shar: Warning - test2.c extracted with wrong size
fi
fi
# end of shell archive
exit 0
--- Cut Here --- Cut Here --- Cut Here --- Cut Here --- Cut Here ---
in response to the questions on the legality .....
>is this legal?
	Yes.
>possible but not legal??
	Irrelevant (see above).
>done every day??
	Probably not.
--
		dg@wrs.UUCP - David Goodenough

					+---+
					| +-+-+
					+-+-+ |
					  +---+