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.