Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #396068 > unrolled thread

function pointer question

Started byMichael Sanders <porkchop@invalid.foo>
First post2026-01-02 07:24 +0000
Last post2026-01-02 19:44 +0000
Articles 20 on this page of 72 — 16 participants

Back to article view | Back to comp.lang.c


Contents

  function pointer question Michael Sanders <porkchop@invalid.foo> - 2026-01-02 07:24 +0000
    Re: function pointer question Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-01-02 09:04 +0000
      Re: function pointer question Michael Sanders <porkchop@invalid.foo> - 2026-01-02 14:42 +0000
      Re: function pointer question Michael Sanders <porkchop@invalid.foo> - 2026-01-02 14:45 +0000
    Re: function pointer question Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-01-02 02:52 -0800
      Re: function pointer question Michael Sanders <porkchop@invalid.foo> - 2026-01-02 14:43 +0000
        Re: function pointer question highcrew <high.crew3868@fastmail.com> - 2026-01-02 17:21 +0100
          Re: function pointer question Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-01-02 09:37 -0800
          Re: function pointer question Ben Bacarisse <ben@bsb.me.uk> - 2026-01-03 03:33 +0000
            Re: function pointer question Andrey Tarasevich <noone@noone.net> - 2026-01-03 07:41 -0800
              Re: function pointer question Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-01-03 21:46 +0000
                Re: function pointer question David Brown <david.brown@hesbynett.no> - 2026-01-04 12:03 +0100
              Re: function pointer question Kaz Kylheku <046-301-5902@kylheku.com> - 2026-01-06 20:41 +0000
                Re: function pointer question Andrey Tarasevich <noone@noone.net> - 2026-01-07 07:18 -0800
                  Re: function pointer question Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-01-07 21:52 -0800
                    Re: function pointer question David Brown <david.brown@hesbynett.no> - 2026-01-08 09:17 +0100
    Re: function pointer question Kaz Kylheku <046-301-5902@kylheku.com> - 2026-01-02 17:48 +0000
      Re: function pointer question Michael Sanders <porkchop@invalid.foo> - 2026-01-02 19:35 +0000
        Re: function pointer question Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-01-02 12:07 -0800
          Re: function pointer question Michael Sanders <porkchop@invalid.foo> - 2026-01-03 06:06 +0000
        Re: function pointer question Kaz Kylheku <046-301-5902@kylheku.com> - 2026-01-02 21:50 +0000
        Re: function pointer question Kaz Kylheku <046-301-5902@kylheku.com> - 2026-01-02 21:52 +0000
          Re: function pointer question "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2026-01-02 14:18 -0800
            Re: function pointer question David Brown <david.brown@hesbynett.no> - 2026-01-03 13:55 +0100
              Re: function pointer question "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2026-01-03 12:04 -0800
                Re: function pointer question Andrey Tarasevich <noone@noone.net> - 2026-01-03 13:01 -0800
                  Re: function pointer question Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-01-07 07:35 -0800
                    Re: function pointer question Andrey Tarasevich <noone@noone.net> - 2026-01-07 08:17 -0800
                      Re: function pointer question Andrey Tarasevich <noone@noone.net> - 2026-01-07 08:23 -0800
                        Re: function pointer question Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-01-07 18:44 -0800
                      Re: function pointer question Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-01-07 18:27 -0800
                Re: function pointer question Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-01-03 22:05 +0000
              Re: function pointer question Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-01-03 16:39 -0800
                Re: function pointer question David Brown <david.brown@hesbynett.no> - 2026-01-04 12:15 +0100
              Re: function pointer question Kaz Kylheku <046-301-5902@kylheku.com> - 2026-01-06 20:33 +0000
                Re: function pointer question Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-01-06 17:01 -0800
          Re: function pointer question Michael Sanders <porkchop@invalid.foo> - 2026-01-03 06:08 +0000
            Re: function pointer question "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2026-01-05 12:40 -0800
              Re: function pointer question Michael Sanders <porkchop@invalid.foo> - 2026-01-06 04:30 +0000
                Re: function pointer question "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2026-01-06 17:05 -0800
        Re: function pointer question James Kuyper <jameskuyper@alumni.caltech.edu> - 2026-01-03 17:20 -0500
          Re: function pointer question Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-01-03 16:48 -0800
          Re: function pointer question Michael Sanders <porkchop@invalid.foo> - 2026-01-05 08:39 +0000
            Re: function pointer question Michael Sanders <porkchop@invalid.foo> - 2026-01-06 12:32 +0000
              Re: function pointer question highcrew <high.crew3868@fastmail.com> - 2026-01-06 13:59 +0100
                Re: function pointer question Michael Sanders <porkchop@invalid.foo> - 2026-01-06 13:57 +0000
                Re: function pointer question antispam@fricas.org (Waldek Hebisch) - 2026-01-06 14:50 +0000
                  Re: function pointer question highcrew <high.crew3868@fastmail.com> - 2026-01-06 21:44 +0100
                    Re: function pointer question scott@slp53.sl.home (Scott Lurndal) - 2026-01-06 22:08 +0000
                      Re: function pointer question Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-01-07 05:59 -0800
                    Re: function pointer question antispam@fricas.org (Waldek Hebisch) - 2026-01-07 09:25 +0000
                      Re: function pointer question David Brown <david.brown@hesbynett.no> - 2026-01-07 11:37 +0100
              Re: function pointer question Michael S <already5chosen@yahoo.com> - 2026-01-06 15:47 +0200
                Re: function pointer question Michael Sanders <porkchop@invalid.foo> - 2026-01-06 14:01 +0000
              Re: function pointer question David Brown <david.brown@hesbynett.no> - 2026-01-06 15:55 +0100
                Re: function pointer question Michael Sanders <porkchop@invalid.foo> - 2026-01-06 16:44 +0000
              Re: function pointer question scott@slp53.sl.home (Scott Lurndal) - 2026-01-06 15:41 +0000
                Re: function pointer question Michael Sanders <porkchop@invalid.foo> - 2026-01-06 16:45 +0000
              Re: function pointer question James Kuyper <jameskuyper@alumni.caltech.edu> - 2026-01-06 10:58 -0500
                Re: function pointer question Michael Sanders <porkchop@invalid.foo> - 2026-01-06 16:49 +0000
                  Re: function pointer question James Kuyper <jameskuyper@alumni.caltech.edu> - 2026-01-06 12:09 -0500
                    Re: function pointer question Michael Sanders <porkchop@invalid.foo> - 2026-01-07 21:18 +0000
                Re: function pointer question Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-01-09 09:14 -0800
                Re: function pointer question Andrey Tarasevich <noone@noone.net> - 2026-01-10 19:17 -0800
                  Re: function pointer question "James Russell Kuyper Jr." <jameskuyper@alumni.caltech.edu> - 2026-01-10 22:39 -0500
                  Re: function pointer question Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-01-11 11:49 -0800
          Re: function pointer question James Kuyper <jameskuyper@alumni.caltech.edu> - 2026-01-05 06:47 -0500
    Re: function pointer question James Kuyper <jameskuyper@alumni.caltech.edu> - 2026-01-02 14:03 -0500
      Re: function pointer question Michael Sanders <porkchop@invalid.foo> - 2026-01-02 19:41 +0000
    Re: function pointer question bart <bc@freeuk.com> - 2026-01-02 19:18 +0000
      Re: function pointer question Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-01-02 11:43 -0800
      Re: function pointer question Michael Sanders <porkchop@invalid.foo> - 2026-01-02 19:44 +0000

Page 1 of 4  [1] 2 3 4  Next page →


#396068 — function pointer question

FromMichael Sanders <porkchop@invalid.foo>
Date2026-01-02 07:24 +0000
Subjectfunction pointer question
Message-ID<10j7rs6$7c9e$1@dont-email.me>
i have:

void moo(char HISTORY[][64], int hst_len, int invalid, const char *gme_msg)

void mastermind(char HISTORY[][64], int hst_len, int invalid, const char *gme_msg)

to use either i have:

void (*render)(char [][64], int, int, const char *) = MOO ? moo : mastermind;

my multi-part question:

why is void required for the function pointer?

A: because both moo() & mastermind return void?

B: because every function must have a return type
   *including function pointers*?

C: what about tyedef?

-- 
:wq
Mike Sanders

[toc] | [next] | [standalone]


#396069

FromLawrence D’Oliveiro <ldo@nz.invalid>
Date2026-01-02 09:04 +0000
Message-ID<10j81nf$9083$2@dont-email.me>
In reply to#396068
On Fri, 2 Jan 2026 07:24:55 -0000 (UTC), Michael Sanders wrote:

> B: because every function must have a return type
>    *including function pointers*?

Yes. The type of the function pointer is of course that of the type of
functions it points to.

> C: what about ty[p]edef?

The same rule applies as with any typedef: put the name to be given to
the type in the place where the variable you might be declaring of
that type would go.

[toc] | [prev] | [next] | [standalone]


#396074

FromMichael Sanders <porkchop@invalid.foo>
Date2026-01-02 14:42 +0000
Message-ID<10j8lgk$fgsk$1@dont-email.me>
In reply to#396069
On Fri, 2 Jan 2026 09:04:47 -0000 (UTC), Lawrence D’Oliveiro wrote:

> On Fri, 2 Jan 2026 07:24:55 -0000 (UTC), Michael Sanders wrote:
> 
>> B: because every function must have a return type
>>    *including function pointers*?
> 
> Yes. The type of the function pointer is of course that of the type of
> functions it points to.
> 
>> C: what about ty[p]edef?
> 
> The same rule applies as with any typedef: put the name to be given to
> the type in the place where the variable you might be declaring of
> that type would go.

Many thanks Lawrence, slow & steady, I'm gaining steam.

-- 
:wq
Mike Sanders

[toc] | [prev] | [next] | [standalone]


#396076

FromMichael Sanders <porkchop@invalid.foo>
Date2026-01-02 14:45 +0000
Message-ID<10j8lmv$fhr0$1@dont-email.me>
In reply to#396069
On Fri, 2 Jan 2026 09:04:47 -0000 (UTC), Lawrence D’Oliveiro wrote:

>> C: what about ty[p]edef?

[sic!]

-- 
:wq
Mike Sanders

[toc] | [prev] | [next] | [standalone]


#396071

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2026-01-02 02:52 -0800
Message-ID<878qeguw0p.fsf@example.invalid>
In reply to#396068
Michael Sanders <porkchop@invalid.foo> writes:
> i have:
>
> void moo(char HISTORY[][64], int hst_len, int invalid, const char *gme_msg)
>
> void mastermind(char HISTORY[][64], int hst_len, int invalid, const char *gme_msg)
>
> to use either i have:
>
> void (*render)(char [][64], int, int, const char *) = MOO ? moo : mastermind;
>
> my multi-part question:
>
> why is void required for the function pointer?

Every function has a type.  Every function pointer has a type.  For a
function pointer to point to a function, it must have type "pointer to
blah", where "blah" is the type of the function.

A function type includes information about the type of the function's
result and the types of its parameters.  The type of both foo and
mastermind can be written as:

    void(char[]64], int, int, const char*)

> A: because both moo() & mastermind return void?

Yes.

> B: because every function must have a return type
>    *including function pointers*?

Functions and function pointers are of course distinct.  A function is
of function type.  A function pointer is of an object type, specifically
a pointer-to-function type.

Every pointer-to-function type is derived from a function type, and that
function type specifies the type returned by the function -- "void" in
this case.

> C: what about tyedef?

What about it?

You can define a typedef for the function type, which could make the
code a bit simpler.  (It's also common to define a typedef for a
pointer-to-function type, but I prefer to typedef the function type
itself.)

An example based on your code :

```
#include <stdio.h>

void moo(char HISTORY[][64], int hst_len, int invalid, const char *gme_msg) {
    puts("moo");
}

void mastermind(char HISTORY[][64], int hst_len, int invalid, const char *gme_msg) {
    puts("mastermind");
}

typedef void functype(char [][64], int, int, const char *);

int main(void) {
    for (int MOO = 0; MOO < 2; MOO ++) {
        functype *render = MOO ? moo : mastermind;
        printf("MOO is %s: ", MOO ? "true" : "false");
        render(NULL, 0, 0, "");
    }
}
```

The output :

```
MOO is false: mastermind
MOO is true: moo
```

(Incidentally, all-caps identifiers are most commonly used as macro
names, with FILE being a notable exception.)

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#396075

FromMichael Sanders <porkchop@invalid.foo>
Date2026-01-02 14:43 +0000
Message-ID<10j8liu$fgsk$2@dont-email.me>
In reply to#396071
On Fri, 02 Jan 2026 02:52:22 -0800, Keith Thompson wrote:

> Michael Sanders <porkchop@invalid.foo> writes:
>> i have:
>>
>> void moo(char HISTORY[][64], int hst_len, int invalid, const char *gme_msg)
>>
>> void mastermind(char HISTORY[][64], int hst_len, int invalid, const char *gme_msg)
>>
>> to use either i have:
>>
>> void (*render)(char [][64], int, int, const char *) = MOO ? moo : mastermind;
>>
>> my multi-part question:
>>
>> why is void required for the function pointer?
> 
> Every function has a type.  Every function pointer has a type.  For a
> function pointer to point to a function, it must have type "pointer to
> blah", where "blah" is the type of the function.
> 
> A function type includes information about the type of the function's
> result and the types of its parameters.  The type of both foo and
> mastermind can be written as:
> 
>     void(char[]64], int, int, const char*)
> 
>> A: because both moo() & mastermind return void?
> 
> Yes.
> 
>> B: because every function must have a return type
>>    *including function pointers*?
> 
> Functions and function pointers are of course distinct.  A function is
> of function type.  A function pointer is of an object type, specifically
> a pointer-to-function type.
> 
> Every pointer-to-function type is derived from a function type, and that
> function type specifies the type returned by the function -- "void" in
> this case.
> 
>> C: what about tyedef?
> 
> What about it?
> 
> You can define a typedef for the function type, which could make the
> code a bit simpler.  (It's also common to define a typedef for a
> pointer-to-function type, but I prefer to typedef the function type
> itself.)
> 
> An example based on your code :
> 
> ```
> #include <stdio.h>
> 
> void moo(char HISTORY[][64], int hst_len, int invalid, const char *gme_msg) {
>     puts("moo");
> }
> 
> void mastermind(char HISTORY[][64], int hst_len, int invalid, const char *gme_msg) {
>     puts("mastermind");
> }
> 
> typedef void functype(char [][64], int, int, const char *);
> 
> int main(void) {
>     for (int MOO = 0; MOO < 2; MOO ++) {
>         functype *render = MOO ? moo : mastermind;
>         printf("MOO is %s: ", MOO ? "true" : "false");
>         render(NULL, 0, 0, "");
>     }
> }
> ```
> 
> The output :
> 
> ```
> MOO is false: mastermind
> MOO is true: moo
> ```
> 
> (Incidentally, all-caps identifiers are most commonly used as macro
> names, with FILE being a notable exception.)

Excellent reply, appreciate it (especially examples).

-- 
:wq
Mike Sanders

[toc] | [prev] | [next] | [standalone]


#396077

Fromhighcrew <high.crew3868@fastmail.com>
Date2026-01-02 17:21 +0100
Message-ID<10j8r9n$ha1t$1@dont-email.me>
In reply to#396075
On 1/2/26 3:43 PM, Michael Sanders wrote:
> (It's also common to define a typedef for a
> pointer-to-function type, but I prefer to typedef the function type
> itself

OK, that's crazy! I didn't know of this!

It seems a bit weird at first, but I like the type consistency:
you declare `typedef int callback(int)` and declare `callback *c`
making it very explicit that we are talking of a pointer.

On the other hand it is not clear what `callback c` should do,
but it makes sense as soon as you declare it.

Thanks for sharing!

-- 
High Crew

[toc] | [prev] | [next] | [standalone]


#396080

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2026-01-02 09:37 -0800
Message-ID<874ip3vrua.fsf@example.invalid>
In reply to#396077
highcrew <high.crew3868@fastmail.com> writes:
> On 1/2/26 3:43 PM, Michael Sanders wrote:
>> (It's also common to define a typedef for a
>> pointer-to-function type, but I prefer to typedef the function type
>> itself
>
> OK, that's crazy! I didn't know of this!

I wrote the above ("It's also common..."), not Michael.

> Thanks for sharing!

You're welcome.

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#396096

FromBen Bacarisse <ben@bsb.me.uk>
Date2026-01-03 03:33 +0000
Message-ID<87ms2v8j4t.fsf@bsb.me.uk>
In reply to#396077
highcrew <high.crew3868@fastmail.com> writes:

> On 1/2/26 3:43 PM, Michael Sanders wrote:
>> (It's also common to define a typedef for a
>> pointer-to-function type, but I prefer to typedef the function type
>> itself
>
> OK, that's crazy! I didn't know of this!
>
> It seems a bit weird at first, but I like the type consistency:
> you declare `typedef int callback(int)` and declare `callback *c`
> making it very explicit that we are talking of a pointer.
>
> On the other hand it is not clear what `callback c` should do,
> but it makes sense as soon as you declare it.

Declarations using the function type do often make sense.  Note
"declarations" -- you can't use the typedef'd name to /define/ a function
of the given type.

A pattern I've used more than once when setting up a table of function
pointers that act like op-codes.  Maybe you have an add function, a sub
function, a mul functions and a div function.  These are all defined in
a file arithmetic.c, but the table (maybe in another file) needs to see
declarations of the names:

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 } 
};

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#396111

FromAndrey Tarasevich <noone@noone.net>
Date2026-01-03 07:41 -0800
Message-ID<10jbdbd$1b3h1$1@dont-email.me>
In reply to#396096
On Fri 1/2/2026 7:33 PM, Ben Bacarisse wrote:
> 
> A pattern I've used more than once when setting up a table of function
> pointers that act like op-codes.  Maybe you have an add function, a sub
> function, a mul functions and a div function.  These are all defined in
> a file arithmetic.c, but the table (maybe in another file) needs to see
> declarations of the names:
> 
> 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;

is already a proper bunch of non-defining function declarations. 
`extern` does not make it more "non-defining" than it already is.

-- 
Best regards,
Andrey.

[toc] | [prev] | [next] | [standalone]


#396120

FromLawrence D’Oliveiro <ldo@nz.invalid>
Date2026-01-03 21:46 +0000
Message-ID<10jc2mv$1i4ia$3@dont-email.me>
In reply to#396111
On Sat, 3 Jan 2026 07:41:33 -0800, Andrey Tarasevich wrote:

> ... with a remark that `extern` is completely redundant here.

One of those quirks of C, that “extern” means something in some
places, but is redundant in others.

[toc] | [prev] | [next] | [standalone]


#396138

FromDavid Brown <david.brown@hesbynett.no>
Date2026-01-04 12:03 +0100
Message-ID<10jdhdo$1ui8e$1@dont-email.me>
In reply to#396120
On 03/01/2026 22:46, Lawrence D’Oliveiro wrote:
> On Sat, 3 Jan 2026 07:41:33 -0800, Andrey Tarasevich wrote:
> 
>> ... with a remark that `extern` is completely redundant here.
> 
> One of those quirks of C, that “extern” means something in some
> places, but is redundant in others.

It is redundant here to the compiler, but might still be helpful to 
human readers.

[toc] | [prev] | [next] | [standalone]


#396228

FromKaz Kylheku <046-301-5902@kylheku.com>
Date2026-01-06 20:41 +0000
Message-ID<20260106123503.456@kylheku.com>
In reply to#396111
On 2026-01-03, Andrey Tarasevich <noone@noone.net> wrote:
> On Fri 1/2/2026 7:33 PM, Ben Bacarisse wrote:
>> 
>> A pattern I've used more than once when setting up a table of function
>> pointers that act like op-codes.  Maybe you have an add function, a sub
>> function, a mul functions and a div function.  These are all defined in
>> a file arithmetic.c, but the table (maybe in another file) needs to see
>> declarations of the names:
>> 
>> 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.

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 };


-- 
TXR Programming Language: http://nongnu.org/txr
Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
Mastodon: @Kazinator@mstdn.ca

[toc] | [prev] | [next] | [standalone]


#396264

FromAndrey Tarasevich <noone@noone.net>
Date2026-01-07 07:18 -0800
Message-ID<10jltg8$nqav$1@dont-email.me>
In reply to#396228
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)?

> 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?

-- 
Best regards,
Andrey

[toc] | [prev] | [next] | [standalone]


#396294

FromTim Rentsch <tr.17687@z991.linuxsc.com>
Date2026-01-07 21:52 -0800
Message-ID<86h5swodm7.fsf@linuxsc.com>
In reply to#396264
Andrey Tarasevich <noone@noone.net> 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.

[toc] | [prev] | [next] | [standalone]


#396295

FromDavid Brown <david.brown@hesbynett.no>
Date2026-01-08 09:17 +0100
Message-ID<10jnp6u$1ac1b$1@dont-email.me>
In reply to#396294
On 08/01/2026 06:52, Tim Rentsch wrote:
> Andrey Tarasevich <noone@noone.net> 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.
> 

I use a different rule that is more consistent - at least for the way I 
organise my code.  For different organisations of code and files, it 
might not work as well.

Any function or object that is to be externally linked is declared with 
"extern" in an appropriate header (usually "file.h", where the 
definition is in "file.c", but there are occasional exceptions).  Inside 
the C file, functions and objects are defined either with "static" (for 
internal linkage) or without a storage class specifier (for external 
linkage).  The C file always includes the header that declares its 
extern functions and objects, so that the compiler can check for 
consistency.

If I need to have a forward declaration of a static function (I rarely 
do, but that can vary by coding style), the forward declaration is made 
"static" and the function definition is also marked "static".  While you 
could omit the "static" on the definition after a forward declaration, I 
think it is good to keep it for consistency and clarity (similar to the 
use of "extern" on function declarations in headers).


The result is greater consistency than your scheme, and without the need 
for a redundant table of forward declarations for static functions.  (I 
have never really understood why some people like such lists - they give 
no new information, force you to jump around back and forth in the file 
when adding or changing functions, can easily get inconsistent, and tell 
you nothing that you can't easily see with any half-decent IDE or 
programmer's editor).


And the scheme can easily be checked with gcc warning flags:

	-Wredundant-decls
	-Wmissing-declarations

[toc] | [prev] | [next] | [standalone]


#396081

FromKaz Kylheku <046-301-5902@kylheku.com>
Date2026-01-02 17:48 +0000
Message-ID<20260102091518.226@kylheku.com>
In reply to#396068
On 2026-01-02, Michael Sanders <porkchop@invalid.foo> wrote:
> B: because every function must have a return type
>    *including function pointers*?

What it is you think type is, in the context of C?

Does type survive into run-time?

If a function pointer is missing type information about return type, and
that function pointer is needed for expressing a function call, where
does the compiler get the type from?

> C: what about tyedef?

What do you think /that/ is?

The typedef declaration is a way of introducing a name, which names a
type, and can then be used in a declaration, or in the cast notation.
The name is an alias for that type.

typedef isn't a type defining mechanism; it is a mechanism for defining
alias names for types ("typedef names" or "typedefs"). The types that
are aliased by typedef names are specified in the ordinary declaration
syntax, the same as like when a variable is being declared rather than a
typedef name.

Syntactically, typedef is a "storage class specifier", like "extern"
or "static". Thus "extern typedef int x" would never make sense,
due to storage class specifiers being exclusive.

-- 
TXR Programming Language: http://nongnu.org/txr
Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
Mastodon: @Kazinator@mstdn.ca

[toc] | [prev] | [next] | [standalone]


#396084

FromMichael Sanders <porkchop@invalid.foo>
Date2026-01-02 19:35 +0000
Message-ID<10j96mn$jrsp$1@dont-email.me>
In reply to#396081
On Fri, 2 Jan 2026 17:48:16 -0000 (UTC), Kaz Kylheku wrote:

> On 2026-01-02, Michael Sanders <porkchop@invalid.foo> wrote:
>> B: because every function must have a return type
>>    *including function pointers*?
> 
> What it is you think type is, in the context of C?
> 
> Does type survive into run-time?
> 
> If a function pointer is missing type information about return type, and
> that function pointer is needed for expressing a function call, where
> does the compiler get the type from?

Its void that's throwing me Kaz. I'm not sure what to think when
it comes to void pointers.

A void pointer (the pointer itself) is not of the type
it points to no? Its typeless & unknown at compile time

A 'normal' pointer in C is a variable that stores the address
of another variable. And *is of the type it points to*...

char str[] = "learning publicly is a humbling experience.";
char *ptr = str;

Then void enters stage left...

void *genericPointer;

It can point to an integer, a character, a structure, or any other type.

void *genericPointer = &intValue; 
void *genericPointer = str[];

And it seems to survive a lack of type at compile time.
Man I'm confused on this. I mean I get void is flexible,
but 'void' is not void in any sense... its like a mask in some
way (I'm groping for a definition) I need to study void more.

-- 
:wq
Mike Sanders

[toc] | [prev] | [next] | [standalone]


#396088

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2026-01-02 12:07 -0800
Message-ID<87v7hju6c9.fsf@example.invalid>
In reply to#396084
Michael Sanders <porkchop@invalid.foo> writes:
> On Fri, 2 Jan 2026 17:48:16 -0000 (UTC), Kaz Kylheku wrote:
>> On 2026-01-02, Michael Sanders <porkchop@invalid.foo> wrote:
>>> B: because every function must have a return type
>>>    *including function pointers*?
>> 
>> What it is you think type is, in the context of C?
>> 
>> Does type survive into run-time?
>> 
>> If a function pointer is missing type information about return type, and
>> that function pointer is needed for expressing a function call, where
>> does the compiler get the type from?
>
> Its void that's throwing me Kaz. I'm not sure what to think when
> it comes to void pointers.

There were no void pointers in the original code.  There were function
pointers to functions that return void.

> A void pointer (the pointer itself) is not of the type
> it points to no? Its typeless & unknown at compile time

No pointer is of the type it points to.  `int` and `int*` are distinct
types.  (The latter is "derived" from the former.)

> A 'normal' pointer in C is a variable that stores the address
> of another variable.

Yes, if by "pointer" you mean "pointer object".  The standard also uses
the word "pointer" for a *value* of pointer type, for example the result
of a call to malloc().

(The word "variable" is tricky, and the standard rarely uses it.
"Object" is less ambiguous.)

>                      And *is of the type it points to*...

No.

> char str[] = "learning publicly is a humbling experience.";
> char *ptr = str;

And now you're introducing array-to-pointer conversion, a can of
worms that I suggest needn't be opened at this time.  A simpler
example:

    char c = 'l';
    char *ptr = &c;

> Then void enters stage left...
>
> void *genericPointer;
>
> It can point to an integer, a character, a structure, or any other type.
>
> void *genericPointer = &intValue;

"intObject" would be a better name.  An object (variable you like)
is not a value; it holds a value.

> void *genericPointer = str[];

That's a syntax error, but it's ok if you drop the "[]".

void* is a distinct type.  Unlike (most) other object pointer types, it
can't be dereferenced, because it doesn't specify a directly usable type
for the object it points to.

Given:

    int n = 42;
    int  *ip = &n;
    void *vp = &n;

ip points to n.  vp, in a sense, does not, but converting vp
from void* to int* yields a pointer value that does point to n.
A void* holds something you can think of as a raw untyped address.
It doesn't point to anything, but converting it to foo* gives you
a pointer to an object of type foo.

> And it seems to survive a lack of type at compile time.
> Man I'm confused on this. I mean I get void is flexible,
> but 'void' is not void in any sense... its like a mask in some
> way (I'm groping for a definition) I need to study void more.

"void" is an incomplete type that cannot be completed.
"void*" is a pointer type with some special characteristics.

First, a value of any object pointer type can be converted to void* and
back again, yielding the original pointer value.  This is not guaranteed
for (most) other pointer types.  For example, converting a char* value
to int* can lose information.  (On most real-world systems, all object
pointers, and often all function pointers as well, have the same
representation, but the standard doesn't guarantee this.)

Second, conversions between void* and other object pointer types are
often performed implicitly.  You can have an object pointer on one
side of an assignment and a void* pointer on the other side.  On some
(exotic) systems, this conversion might do something more than just
copying the representation.

The character pointer types char*, signed char*, and unsigned char*
share the first characteristic, but not the second.  (In very early
(pre-ANSI) C, char* was commonly used as a generic pointer type before
void and void* were introduced.)

Every pointer value, object, or expression has a well defined type,
specifically a pointer type.  That type specifies the type of
the object it points to -- unless the pointer is of type void*.
(Or it can point to a function; object pointers and function pointers
are distinct.)

The comp.lang.c FAQ <https://www.c-faq.com/> has some good information,
though some of it is a bit dated.  Section 4 covers pointers, and
section 6 covers arrays and pointers.

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#396099

FromMichael Sanders <porkchop@invalid.foo>
Date2026-01-03 06:06 +0000
Message-ID<10jabkh$11n14$1@dont-email.me>
In reply to#396088
On Fri, 02 Jan 2026 12:07:02 -0800, Keith Thompson wrote:

> The comp.lang.c FAQ <https://www.c-faq.com/> has some good information,
> though some of it is a bit dated.  Section 4 covers pointers, and
> section 6 covers arrays and pointers.

Sure enough, plan on reading that Monday. Thanks.

-- 
:wq
Mike Sanders

[toc] | [prev] | [next] | [standalone]


Page 1 of 4  [1] 2 3 4  Next page →

Back to top | Article view | comp.lang.c


csiph-web