[comp.lang.c] declarations in include files: how do YOU feel?

jwp@larry.sal.wisc.edu (Jeffrey W Percival) (05/11/89)

I would like to find out how the "experts" feel about a coding
practice, so I don't develop a bizarre style (bizarre with respect
to the general body of usage).  I hope this doesn't start a
philosophy war of some kind.

The situation is, suppose I have a bunch of routines that are packaged
into a lib.a, and there is an associated include file "lib.h" that
users need to include.  Should the lib.h file contain extern declarations
for everything in lib.a, or not?

case 1:  shotgun approach.  declare all the routines contained in lib.a
advantage:  user doesn't need to.
disadvantage: "scope" is not micro-managed.  labels are in scope
everywhere, even labels not used in actual references.

case 2:  "anal" approach.  no declarations in lib.h.  User needs
to type in the declarations in every function that makes a reference.
advantage (???): user sees declarations in same file as usage.
scope of labels is managed according to program design.

If my goal is to be portable and non-eccentric, what should I do?
-- 
Jeff Percival (jwp@larry.sal.wisc.edu)

scs@sloth.pika.mit.edu (Steve Summit) (05/11/89)

In article <179@larry.sal.wisc.edu> jwp@larry.sal.wisc.edu (Jeffrey W Percival) writes:
>The situation is, suppose I have a bunch of routines that are packaged
>into a lib.a, and there is an associated include file "lib.h" that
>users need to include.  Should the lib.h file contain extern declarations
>for everything in lib.a?

By all means.  I'd say that this is the recommended standard
practice.  If you're using ANSI-style function prototypes, put
the prototypes in too, of course.  If you're not using
prototypes, you may leave out extern declarations for those
functions returning int.  (You may also leave them in, for
documentation purposes.)

>disadvantage: "scope" is not micro-managed.  labels are in scope
>everywhere, even labels not used in actual references.

I've never worried about micro-managing global scope.
If it's extern, it's global, so any module may call it.
Explicitly announcing their intention to call it (with their own
extern declaration) doesn't provide much more information than
does the actual call.  (For the same reason, I think that extern
declarations in local scopes are silly.  I understand that many
people like them, but I've never really understood why.)

>case 2:  "anal" approach.  no declarations in lib.h.  User needs
>to type in the declarations in every function that makes a reference.
>advantage (???): user sees declarations in same file as usage.
>scope of labels is managed according to program design.

The disadvantage here, which is that the declaration (and, worse,
the prototype, if used) has to be replicated, with ripe
possibility for error, especially if the declaration has to be
changed.  This disadvantage, I would think, far outweighs any
loss of "micro scoping" caused by header file externs.

                                            Steve Summit
                                            scs@adam.pika.mit.edu

rwberry@hubcap.clemson.edu (Robert W Berry) (05/11/89)

From article <11318@bloom-beacon.MIT.EDU>, by scs@sloth.pika.mit.edu (Steve Summit):
> In article <179@larry.sal.wisc.edu> jwp@larry.sal.wisc.edu (Jeffrey W Percival) writes:

    ... include variable declarations in header file? ...

> 
> By all means.  I'd say that this is the recommended standard
> practice.  If you're using ANSI-style function prototypes, put
> the prototypes in too, of course.  If you're not using
> prototypes, you may leave out extern declarations for those
> functions returning int.  (You may also leave them in, for
> documentation purposes.)

     Is it?  I thought the more general practice was to define the
variable types (structures, unions, etc.) and have the programmer
declare a variable of the appropriate type for use in his function.
Look at file pointers (of type FILE *) that you declare for stream I/O,
low-level structures (such as REGS in Turbo C), windowing libraries
often have a structure called "window" that is manipulated by the
library rountines.

     I definitely vote yes on having prototypes in the header file (if
you're into prototypes that is).  But declaring variables there scares 
me a little.  (And there's always the nasty possibity of duplicating a 
variable name -- although this already happens with certain structure 
names in header files.)

     Bob

-- 
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-=- Bob Berry -=- PC-Guru's Inc.         ! rwberry@hubcap.clemson.edu   -=-
-=- We are the science of modern motion. ! 803-654-7623 || 803-656-2635 -=-
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

jwp@larry.sal.wisc.edu (Jeffrey W Percival) (05/12/89)

In article <11318@bloom-beacon.MIT.EDU> scs@athena.mit.edu (Steve Summit) writes:
>In article <179@larry.sal.wisc.edu> jwp@larry.sal.wisc.edu (Jeffrey W Percival) writes:
>>Should the lib.h file contain extern declarations for everything in lib.a?
>By all means.
>I've never worried about micro-managing global scope.
>If it's extern, it's global, so any module may call it.

Thanks for the response.  Is this the general consensus?

Another question on this style:  does one include lib.h in the
subroutine files that make up lib.a?  That is, if lib.h contains
an "extern char foo()" and foo.c includes lib.h and then goes
on to define foo, is this a problem?
-- 
Jeff Percival (jwp@larry.sal.wisc.edu)

henry@utzoo.uucp (Henry Spencer) (05/12/89)

In article <179@larry.sal.wisc.edu> jwp@larry.sal.wisc.edu (Jeffrey W Percival) writes:
>The situation is, suppose I have a bunch of routines that are packaged
>into a lib.a, and there is an associated include file "lib.h" that
>users need to include.  Should the lib.h file contain extern declarations
>for everything in lib.a, or not?

Yes.  It's more convenient to the user to have all the declarations gotten
right for him (especially significant when ANSI prototypes become common)
than to have to do them himself, even though this theoretically allows him
to conserve name space.  Having to type such things in yourself almost
invariably leads to shortcuts and sloppiness, too.
-- 
Mars in 1980s:  USSR, 2 tries, |     Henry Spencer at U of Toronto Zoology
2 failures; USA, 0 tries.      | uunet!attcan!utzoo!henry henry@zoo.toronto.edu

gwyn@smoke.BRL.MIL (Doug Gwyn) (05/12/89)

In article <179@larry.sal.wisc.edu> jwp@larry.sal.wisc.edu (Jeffrey W Percival) writes:
>The situation is, suppose I have a bunch of routines that are packaged
>into a lib.a, and there is an associated include file "lib.h" that
>users need to include.  Should the lib.h file contain extern declarations
>for everything in lib.a, or not?

If the library is naturally divisible into smaller packages (e.g. array
operations, error reporting, ...) then provide a separate header for
each "package" that defines/declares things for just that package.
Otherwise, define/declare them all in lib.h.  If functions in lib.a
can call other functions in lib.a, the user has to be aware of the
total set of external names defined by the library anyway so that he
doesn't accidentally usurp one for his application.  (That would break
functions that called that usurped function.)

Just because a header includes a declaration of a function does not mean
that the function will be linked into the executable image; only if it
(or some other external defined in the same object module) is referred
to will the corresponding object module be linked in.  (There are some
linkers that violate this model, but it's pretty near universally agreed
that they're broken.)

jwp@larry.sal.wisc.edu (Jeffrey W Percival) (05/12/89)

In article <10251@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn) writes:
>In article <179@larry.sal.wisc.edu> jwp@larry.sal.wisc.edu (Jeffrey W Percival) writes:
>>Should the lib.h file contain extern declarations for everything in lib.a?
>Otherwise, define/declare them all in lib.h.  If functions in lib.a
>can call other functions in lib.a, the user has to be aware of the
>total set of external names defined by the library anyway so that he
>doesn't accidentally usurp one for his application.  (That would break
>functions that called that usurped function.)

This appears to be the consensus, and it makes sense.  Thanks.

And besides, I think I thought up another reason:  what if the maintainer
of the lib.a decides to re-implement an existing function as a macro,
for example.  If the user has the thing appearing in an extern statement,
it might break.  If the user relies on the lib.h file to "make everything
OK", then the macro/function sleight of hand can proceed behind the scenes.

Is that interpretation unflawed?
-- 
Jeff Percival (jwp@larry.sal.wisc.edu)

mat@mole-end.UUCP (Mark A Terribile) (05/12/89)

> I would like to find out how the "experts" feel about a coding practice, so
> I don't develop a bizarre style (bizarre with respect to the general body of
> usage).  I hope this doesn't start a philosophy war of some kind.

It will, never fear.  I hereby fire the first salvo.

> ... suppose I have a bunch of routines ... packaged into a lib.a, and there
> is an associated include file "lib.h" ...  Should the lib.h file contain
> extern declarations for everything in lib.a, or not?

> case 1:  shotgun approach.  declare all the routines contained in lib.a
> advantage:  user doesn't need to.
> disadvantage: "scope" is not micro-managed.  labels are in scope
> everywhere, even labels not used in actual references.

Advantage: the declarations are available and they are *RIGHT*.  When the
system is changed or ported, the correct versions are available to all
programs that use them.  This is important for obvious reasons; it's even
more important for ANSI C.
 
> case 2:  "anal" approach.  no declarations in lib.h.  User needs
> to type in the declarations in every function that makes a reference.
> advantage (???): user sees declarations in same file as usage.

Not an advantage.  The programmer has to get them right and he's got no
machine checking (save, possibly for LINT, which, IMnsHO, is a botch and a
disfigurement).

> scope of labels is managed according to program design.

How is this an advantage?  If you really feel that you need it, use #ifdef's
to surround ``reasonable'' groups of function names--and #else's controlling
#define's that will make the programs invalid if they need a declaration and
don't have it.

> If my goal is to be portable and non-eccentric, what should I do?

If your goal is to write reliable software, which should you do?
-- 

(This man's opinions are his own.)
From mole-end				Mark Terribile

diamond@diamond.csl.sony.junet (Norman Diamond) (05/12/89)

In article <180@larry.sal.wisc.edu> jwp@larry.sal.wisc.edu.UUCP (Jeffrey W Percival) writes:

>Another question on this style:  does one include lib.h in the
>subroutine files that make up lib.a?

Yes.

>That is, if lib.h contains
>an "extern char foo()" and foo.c includes lib.h and then goes
>on to define foo, is this a problem?

In K&R-I and ANSI and any non-broken compiler, it is specifically
permitted.  (Although K&R-I indirectly contradicts itself on this
point, it directly states that this is permitted.)

--
Norman Diamond, Sony Computer Science Lab (diamond%csl.sony.co.jp@relay.cs.net)
  The above opinions are my own.   |  Why are programmers criticized for
  If they're also your opinions,   |  re-implementing the wheel, when car
  you're infringing my copyright.  |  manufacturers are praised for it?

andre@targon.UUCP (andre) (05/12/89)

In article <180@larry.sal.wisc.edu> jwp@larry.sal.wisc.edu.UUCP (Jeffrey W Percival) writes:
>Another question on this style:  does one include lib.h in the
>subroutine files that make up lib.a?  That is, if lib.h contains
>an "extern char foo()" and foo.c includes lib.h and then goes
>on to define foo, is this a problem?

No problem, it is just what you want, if the global prototype is used
in the file where the function is defined, the compiler will complain
when the prototype and the definition mismatch, thus by including lib.h
in the lib.a modules you let the compiler check all your prototypes for you.

-- 
~----~ |m    AAA         DDDD  It's not the kill, but the thrill of the chase.
~|d1|~@--   AA AAvv   vvDD  DD        Segment registers are for worms.
~----~  &  AAAAAAAvv vvDD  DD
~~~~~~ -- AAA   AAAvvvDDDDDD        Andre van Dalen, uunet!mcvax!targon!andre

henry@utzoo.uucp (Henry Spencer) (05/12/89)

In article <180@larry.sal.wisc.edu> jwp@larry.sal.wisc.edu.UUCP (Jeffrey W Percival) writes:
>... That is, if lib.h contains
>an "extern char foo()" and foo.c includes lib.h and then goes
>on to define foo, is this a problem?

In the absence of errors like type mismatches, no problems will ensue.
In fact, catching things like type mismatches is a very strong reason
to do exactly this.
-- 
Mars in 1980s:  USSR, 2 tries, |     Henry Spencer at U of Toronto Zoology
2 failures; USA, 0 tries.      | uunet!attcan!utzoo!henry henry@zoo.toronto.edu

vlcek@mit-caf.MIT.EDU (Jim Vlcek) (05/14/89)

In article <181@larry.sal.wisc.edu> jwp@larry.sal.wisc.edu.UUCP
(Jeffrey W Percival) writes: 

>what if the maintainer
>of the lib.a decides to re-implement an existing function as a macro,
>for example.  If the user has the thing appearing in an extern statement,
>it might break.  If the user relies on the lib.h file to "make everything
>OK", then the macro/function sleight of hand can proceed behind the scenes.

>Is that interpretation unflawed?

If what was once a function is turned into a macro, programs which
passed arguments with side effects to the function may not work
correctly with the macro.  You know the tune:

#define square(x) ((x)*(x))  /* Used to be a function ... needed speed */

y = square(++i);

Any macro->function sleight of hand had best not take place behind the
scenes, and in fact should probably not take place at all.  Going the
other direction is probably considered safe, although some programs
may have depended upon the side effects of the macro which is now a
function.  Probably anyone who does so deserves to suffer, though...

Jim Vlcek (vlcek@caf.mit.edu  uunet!mit-caf!vlcek)

henry@utzoo.uucp (Henry Spencer) (05/16/89)

In article <2337@mit-caf.MIT.EDU> vlcek@mit-caf.UUCP (Jim Vlcek) writes:
>If what was once a function is turned into a macro, programs which
>passed arguments with side effects to the function may not work
>correctly with the macro...

Normally it's necessary for such macros to be written carefully so that
they invoke each argument exactly once.  Given that, and the constraints
it puts on what can be done in a macro, though, the transformation doesn't
usually cause trouble.
-- 
Subversion, n:  a superset     |     Henry Spencer at U of Toronto Zoology
of a subset.    --J.J. Horning | uunet!attcan!utzoo!henry henry@zoo.toronto.edu

garys@bunker.UUCP (Gary M. Samuelson) (05/16/89)

In article <181@larry.sal.wisc.edu> jwp@larry.sal.wisc.edu.UUCP (Jeffrey W Percival) writes:
>And besides, I think I thought up another reason:  what if the maintainer
>of the lib.a decides to re-implement an existing function as a macro,
>for example.  If the user has the thing appearing in an extern statement,
>it might break.  If the user relies on the lib.h file to "make everything
>OK", then the macro/function sleight of hand can proceed behind the scenes.

Not necessarily.

There are other cases where changing a function to a macro
can cause problems:

First, if a function is replaced with a macro, it is no longer in lib.a.
Therefore, programs have to be recompiled, as opposed to merely relinking.
This can be ameliorated by well-written make files (assuming make is
available), but should be taken into account when considering changing
a function to a macro.

Second, a pointer to a function can be passed as a parameter, stored in
a variable, and so forth.  Any such usage will break with a macro.

Third, the size of the program increases as you replace functions
with macros.  Maybe that's not an issue in your particular case, but
in some cases it is, and should be taken into account.

Debugging is also affected adversely; ever try to put a breakpoint
at a macro?

In short, please do not change things by "sleight of hand" or "behind
the scenes."  If you (generic "you" here) change something I use,
I want to know as precisely as possible why, preferably in advance.
And if you are inclined to say that a particular change won't have
any effect on me, well, I prefer that you let me be the judge of that.

Gary Samuelson

mcdaniel@uicsrd.csrd.uiuc.edu (Tim McDaniel) (05/17/89)

In article <5134@bunker.UUCP> garys@bunker.UUCP (Gary M. Samuelson) writes:
>First, if a function is replaced with a macro, it is no longer in lib.a.

What's to prevent it?  In f.c (to go into lib.a):
        #include <lib.h>
        #undef f
        int f(int x, char * y) {
        ... }
That way, it's in lib.h as a macro and lib.a as a function.

>Therefore, programs have to be recompiled, as opposed to merely relinking.
Not in this scheme.  Recompiling would cause some speedup, however, as
well as increasing the code size.

>Second, a pointer to a function can be passed as a parameter, stored in
>a variable, and so forth.  Any such usage will break with a macro.

Not in pANS C.  If "foo" is a macro that requires arguments, and
a use of the token "foo" is not followed by a "(" token, it's not a
macro call.  I just tried this under gcc:
        #include <stdio.h>
        int foo(x) int x; { printf("function %d\n", x); }
        #define foo(y) printf("macro %d\n", y);

        baz(p) int (*p)(); { (*p)(10); }
        main() {
            int (*p)() = foo;
            (*p)(5);
            baz(foo);
            foo(15);
            exit(0);
        }
You should get:
        function 5
        function 10
        macro 15
(unless I screwed up in editing this for posting).  So, in lib.h:
        extern int f(int x, char * y);
        #define f(x,y) ...whatever...
The latter gets used for calls, the former for pointer references.

Alas, "cc" under BSD 4.3 on a VAX doesn't follow that rule.  In that
case, in usercode.c:
        #include <lib.h>
        ... some code ...
        #undef f
        int (*p)() = f;
        ... more references to f as a parameter or as a ptr to func
After the #undef, all references to f are function calls, not macros
-- c'est la vie.  Or define a convention for lib.a: ptr_f is an extern
const variable which contains a pointer to f.

Personally, I use pointers to functions so infrequently that I'm
willing to type a few extra trivial keystrokes to use them.  Your
milage may vary.

>Third, the size of the program increases as you replace functions
>with macros.  Maybe that's not an issue in your particular case, but
>in some cases it is, and should be taken into account.

A tradeoff of time versus space.  If it's a problem in your code (many
calls * large size), use #undef.

>Debugging is also affected adversely; ever try to put a breakpoint
>at a macro?
#undef and recompile.  I usually have to recompile with -g anyway.  If
the problem is the macro itself or its calls (for example, side
effects in the argument list), perhaps it was a mistake to make it a
macro in the first place.

>In short, please do not change things by "sleight of hand" or "behind
>the scenes."  If you (generic "you" here) change something I use,
>I want to know as precisely as possible why, preferably in advance.
>And if you are inclined to say that a particular change won't have
>any effect on me, well, I prefer that you let me be the judge of that.

I suppose that when your vendor upgrades your OS, you read the diffs?
:-) Seriously, a user can't and shouldn't be aware of *everything*
that's going on in the implementation -- that's why libraries and data
encapsulation/hiding are so useful.

--
             Tim, the Bizarre and Oddly-Dressed Enchanter
                    mcdaniel@uicsrd.csrd.uiuc.edu
            {uunet,convex,pur-ee}!uiucuxc!uicsrd!mcdaniel
            mcdaniel%uicsrd@{uxc.cso.uiuc.edu,uiuc.csnet}

henry@utzoo.uucp (Henry Spencer) (05/18/89)

In article <5134@bunker.UUCP> garys@bunker.UUCP (Gary M. Samuelson) writes:
>...if a function is replaced with a macro, it is no longer in lib.a.

Not necessarily.  Standard library functions in fact are required to be
in both places.  Doing this for other functions would also seem sensible.

>Third, the size of the program increases as you replace functions
>with macros...

Not necessarily.  Calling sequences can take a non-trivial amount of
code, and they tend to interfere with optimizing compilers.  The macro
version can end up being smaller.

>Debugging is also affected adversely; ever try to put a breakpoint
>at a macro?

This is a generic problem with most forms of optimization.
-- 
Subversion, n:  a superset     |     Henry Spencer at U of Toronto Zoology
of a subset.    --J.J. Horning | uunet!attcan!utzoo!henry henry@zoo.toronto.edu

garys@bunker.UUCP (Gary M. Samuelson) (05/18/89)

Note that the context of this discussion was the assertion that
changing a function to a macro in some library could be done "behind
the scenes;" i.e., without the user needing to be aware of the change.

In article <1008@garcon.cso.uiuc.edu> mcdaniel@uicsrd.csrd.uiuc.edu
(Tim McDaniel) writes:

>In article <5134@bunker.UUCP> garys@bunker.UUCP (Gary M. Samuelson) writes:
>>First, if a function is replaced with a macro, it is no longer in lib.a.

>What's to prevent it?  In f.c (to go into lib.a):
>        #include <lib.h>
>        #undef f
>        int f(int x, char * y) {
>        ... }
>That way, it's in lib.h as a macro and lib.a as a function.

Then it hasn't been *replaced*, has it?

Having the same symbol be both a macro and a function in the same
file belongs only in Obfuscated C contest entries.

>>Therefore, programs have to be recompiled, as opposed to merely relinking.
>Not in this scheme.  Recompiling would cause some speedup, however, as
>well as increasing the code size.

And if later I recompile for some other reason, my program changes in
ways which I didn't expect.

Also, it is possible that replacing a function with a macro could
actually make the program slower.  For example, because of its increased
size, it page faults or swaps more frequently.

>>Second, a pointer to a function can be passed as a parameter, stored in
>>a variable, and so forth.  Any such usage will break with a macro.

>Not in pANS C.  If "foo" is a macro that requires arguments, and
>a use of the token "foo" is not followed by a "(" token, it's not a
>macro call.

Alright, there exists at least one compiler for which my statement is
false.  So, "Any such usage *may* break with a macro."  When pANS becomes
ANS (i.e., accepted as a standard), are all the existing compilers
which don't have these new features suddenly going be transformed,
or is someone going to upgrade them (gratis)?

>Alas, "cc" under BSD 4.3 on a VAX doesn't follow that rule.

Which means that this feature, specified (presumably required)
by pANS is inherently non-portable and should therefore not be used.

I conjecture that relatively few compilers already incorporate
this feature.

>In that
>case, in usercode.c:
>        #include <lib.h>
>        ... some code ...
>        #undef f
>        int (*p)() = f;
>        ... more references to f as a parameter or as a ptr to func
>After the #undef, all references to f are function calls, not macros
>-- c'est la vie.  Or define a convention for lib.a: ptr_f is an extern
>const variable which contains a pointer to f.

The original contention, which I disputed, was that the function-to-macro
transition could be done "behind the scenes."  Your illustration supports
my position quite well.

>Personally, I use pointers to functions so infrequently...

We are talking about libraries, which are supposed to be used
by lots of people, and therefore should not cater to personal style.

> ...that I'm
>willing to type a few extra trivial keystrokes to use them.

Keystrokes which change the meaning of the program or detract
from its readability are not what I would call trivial.

>>Debugging is also affected adversely; ever try to put a breakpoint
>>at a macro?

>#undef and recompile.  I usually have to recompile with -g anyway.  If
>the problem is the macro itself or its calls (for example, side
>effects in the argument list), perhaps it was a mistake to make it a
>macro in the first place.

The very point I was trying to make, and again supports my contention
that functions should not be changed "behind the scenes."  Such changes
should only be made, if ever, after studying a lot of issues.

>>In short, please do not change things by "sleight of hand" or "behind
>>the scenes."  If you (generic "you" here) change something I use,
>>I want to know as precisely as possible why, preferably in advance.
>>And if you are inclined to say that a particular change won't have
>>any effect on me, well, I prefer that you let me be the judge of that.

>I suppose that when your vendor upgrades your OS, you read the diffs?
>:-)

Don't you?  Yes, if something has changed which has the potential to
affect my entire system, I want to know what changed, so that I can
figure out what I have to change.  If the new version of OS requires
too much work on my part, I won't upgrade, unless the new version
includes a new feature or a bug fix I can't live without.

I certainly want to see specification changes, lists of problems fixed
and features added.

> Seriously, a user can't and shouldn't be aware of *everything*
>that's going on in the implementation -- that's why libraries and data
>encapsulation/hiding are so useful.

Changing a function into a macro is not *everything*, but, as you helped
illustrate, it has the potential to require the user to make changes
in his code, and therefore is something the user needs to be aware of.

Gary Samuelson

mcdaniel@uicsrd.csrd.uiuc.edu (Tim McDaniel) (05/19/89)

In article <5178@bunker.UUCP> garys@bunker.UUCP (Gary M. Samuelson) writes:
>Note that the context of this discussion was the assertion that
>changing a function to a macro in some library could be done "behind
>the scenes;" i.e., without the user needing to be aware of the change.

I think it *can* be done.  Changing a function to a macro must be
considered carefully, as with any proposed optimization.  In other
words, will it really be an optimization, or a problem?  *Any* change
can break code.

- Was the function ever called with arguments with side effects?  If
  so, will the side effects get evaluated exactly once?
- Is the product "macro size (in bytes of machine code)" * "lexical
  number of calls per program" large?  How does "macro size" compare
  with "function call size"?
- Were users ever likely to put the function name in jump tables?  If so,
  are their compilers ANSI C compliant: if a macro name is not
  followed by "(", is it an error?
- Who are the users?  Dave and Perry down the hall, who know to come
  to you if they have any problems with -lcsrd, or all of SUN's UNIX
  customers?
- Have you documented the change?

>>That way, it's in lib.h as a macro and lib.a as a function.
>
>Then it hasn't been *replaced*, has it?

Hidden, in the sense of variable hiding:
        {int i; ... {int i; ... }}

>Having the same symbol be both a macro and a function in the same
>file belongs only in Obfuscated C contest entries.

I think there's something in the ANSI C standard about this -- if
library functions are implemented as macros or builtins, perhaps?
I think #undef is officially blessed for such a case, but I can't
remember any details and I can't find it in K&R2.  I guess we just
have different tastes in coding styles.

>>Personally, I use pointers to functions so infrequently...
>
>We are talking about libraries, which are supposed to be used
>by lots of people, and therefore should not cater to personal style.

Let me rephrase.  "Personally" == "I'd like to know the practices of
all the C programmers in the world, but I don't, so I can only list my
own experiences."  I've see 3 function jump tables in my C programming
life, all of which included only program-defined functions (none out
of any libraries), 2 of which could have had lists of #undefs added
mechanically.

As for "lots of people" using libraries: when I think of "libraries",
I think of everything from libc.a (millions of users, indirectly) down
to libcsrd.a (a local library; dozens of users, maybe).  Changing
function -> macro works FAR better on a local scale.

Looking at your last response, Gary, I'd say we are in substantial
agreement about the basic issues involved.

--
"6:20 O Timothy, keep that which is committed to thy trust, avoiding
profane and vain babblings, and oppositions of science falsely so
called: 6:21 Which some professing have erred concerning the faith."

Tim, the Bizarre and Oddly-Dressed Enchanter  |  mcdaniel@uicsrd.csrd.uiuc.edu
            {uunet,convex,pur-ee}!uiucuxc!uicsrd!mcdaniel
            mcdaniel%uicsrd@{uxc.cso.uiuc.edu,uiuc.csnet}