From: scs@adam.mit.edu (Steve Summit)
Subject: Re: Initialisation code in ANSI C.
Summary: be careful changing function pointers in mid-stream...
Reply-To: scs@adam.mit.edu
Organization: none, at the moment
Date: Thu, 16 Apr 1992 18:46:37 GMT

In article <kumsfiINN1q5@early-bird.think.com>, barmar@think.com
(Barry Margolin) suggests:
> Instead of calling the functions directly, call them through function
> pointers.  All the function pointers would be initialized to a function
> that calls the initialization routine and then calls the corresponding real
> function...
>
> int (*draw_pixel)(int x, int y) = initial_draw_pixel;
>
> static
> int initial_draw_pixel (int x, int y) {
>    initialize();
>    return real_draw_pixel(x, y);
> }
>
> void initialize (void) {
>    /* other initialization ... */
>    draw_pixel = real_draw_pixel;
> }

(Paul Shaw made a similar suggestion.)

I recommend a combination of two techniques, namely adding a
one-shot flag to the initial_draw_pixel routine:

	static int
	initial_draw_pixel (int x, int y) {
		static int beenhere = 0;
		if(!beenhere) {
			initialize();
			beenhere = 1;
		}

		return real_draw_pixel(x, y);
	}

Assuming that the initialization must be performed once *and
only once*, the apparently-redundant test on the static boolean
"beenhere" variable guards against the following potential
anomaly:

Suppose the caller calls draw_pixel (through its pointer) twice
in the same expression:

	nerrs = draw_pixel(x1, y1) + draw_pixel(x2, y2);

(this sort of usage is unlikely for a pixel-drawing routine, but
could be quite natural for other routines).  A huge debate (which
I did not follow) raged on comp.std.c recently concerning the
behavior of a similar expression.  It's obvious that the two
draw_pixel invocations might occur in either order.  We might
think that we don't care -- whichever is first will be the
initializing one.  But note that we have a global pointer-to-
function which is being dereferenced twice within the same
expression, but which is modified by (at least) one of the calls.
What if the compiler (not noticing that the same pointer appears
twice) fetches through the pointer twice (for both the left-hand
and right-hand sides of the addition operator) before calling
(either of) the pointed-to functions?  Or, what if it does notice
that the same pointer appears twice, and caches the value,
overlooking the fact that it could change?  It is conceivable
(note I do not claim that this is necessarily likely or legal)
that initial_draw_pixel could be called twice.

I don't know what the outcome of the comp.std.c debate was, and
I'm too lazy to find out [note 1].  Regardless of the outcome,
however, I don't necessarily trust compiler writers to get such a
subtle issue right, so this is one case where I choose to err on
the side of paranoia and write code which works even if
initial_draw_pixel happens to be called twice.

					Steve Summit
					scs@adam.mit.edu

note 1.  Please don't accuse me of sloth -- this particular act
of laziness is an active, conscious choice.  Similarly, I could
not tell you (without pulling out my copy of the ANSI C Standard)
whether the behavior of

	i = i++ + i++

is unspecified, undefined, or implementation-defined (though
obviously it's at least one of the three [note 2]).  Sure, I
could memorize this answer if I chose to, but I choose not to.
Why bother?  I've got better things to devote active brain cells
to, and in the work I do, the unspecified/undefined/implementation-
defined distinction doesn't matter -- I write portable code, so I
avoid all such behaviors.

note 2.  No followups on the i++ + i++ question, please, nor
replies either -- I'm really not interested.
Newsgroups: comp.lang.c