Path: csiph.com!eternal-september.org!feeder.eternal-september.org!nntp.eternal-september.org!.POSTED!not-for-mail
From: Tim Rentsch
Newsgroups: comp.lang.c
Subject: Re: function pointer question
Date: Wed, 07 Jan 2026 21:52:16 -0800
Organization: A noiseless patient Spider
Lines: 70
Message-ID: <86h5swodm7.fsf@linuxsc.com>
References: <10j7rs6$7c9e$1@dont-email.me> <878qeguw0p.fsf@example.invalid> <10j8liu$fgsk$2@dont-email.me> <10j8r9n$ha1t$1@dont-email.me> <87ms2v8j4t.fsf@bsb.me.uk> <10jbdbd$1b3h1$1@dont-email.me> <20260106123503.456@kylheku.com> <10jltg8$nqav$1@dont-email.me>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Injection-Date: Thu, 08 Jan 2026 05:52:23 +0000 (UTC)
Injection-Info: dont-email.me; posting-host="f646824e109d26d154da12d2f3c25277"; logging-data="1331187"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1/CP17S+6/JzVoYCGMoaHIjE1d8Cuuyv6c="
User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux)
Cancel-Lock: sha1:Xw8Pl5Gnj7hwApL+rQUkkTFK0Fc= sha1:JE3f/fvIScDjF3xnsfO04VempW8=
Xref: csiph.com comp.lang.c:396294
Andrey Tarasevich writes:
> On Tue 1/6/2026 12:41 PM, Kaz Kylheku wrote:
>
>>>> typedef double operation(double, double);
>>>> /* ... */
>>>>
>>>> extern operation add, sub, mul, div;
>>>>
>>>> static struct {
>>>> char *name;
>>>> operation *function;
>>>> } ops[] = {
>>>> { "add", add },
>>>> { "subtract", sub },
>>>> { "multiply", mul },
>>>> { "divide", div }
>>>> };
>>>
>>> ... with a remark that `extern` is completely redundant here.
>>>
>>> operation add, sub, mul, div;
>>
>> Butlonly because operation is a function type, so the concept of
>> a tentative definition doesn't apply.
>
> Yes, to me it feels like it has way less potential to mislead with an
> extern`. But I can't really say whether this perception is objectively
> inherent in the construct, or it is just the fact that it is an exotic
> way of declaring functions (for me and, probably, for most people).
>
> However, while it is true that the concept of a tentative definition
> doesn't apply, I still don't quite get your point. What if were an
> object type and the concept would apply? Are you implying that
> tentative definitions should be avoided (i.e. that all object
> definitions should include an initializer)?
If we ignore "static" for the moment, there is a simple rule:
use 'extern' for declarations, and nothing for definitions.
This rule works for both functions and objects.
Now if we add "static" back into the mix, and limit the discussion
to functions, the same rule applies provided we stipulate that
everything is pre-declared. Thus, always use 'extern' or 'static'
to declare (in advance) a function, and on the function definition
don't use any storage class.
Unfortunately, the way 'static' works for objects is not symmetric.
There is no way to write a non-defining declaration for a static
object. And, what is worse, once an object has been declared (and
so tentatively defined) with 'static', then any definition must also
use 'static'. Hence we have a new rule: always use 'extern' or
'static' when declaring a function or object, and leave off both
when defining a function or object, /except/ 'static' must be used
when defining a static object. C would have been nicer if 'static'
for objects worked the same way as 'static' for functions. Oh well.
>> The lack of extern could trip someone up who refactors the
>> code such that the operations are object types:
>>
>> named_operation add, sub, mul, div; // oops, multiple definition
>>
>> static named_operation ops[] = { add, sub, mul, div };
>
> Again, I'm at a bit of a loss. What is this intended to illustrate?
To me the example looks flawed (and not because of multiple
definitions). My advice is to stick with the rule described above
for declarations and definitions.