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 2 of 4 — ← Prev page 1 [2] 3 4  Next page →


#396091

FromKaz Kylheku <046-301-5902@kylheku.com>
Date2026-01-02 21:50 +0000
Message-ID<20260102114223.811@kylheku.com>
In reply to#396084
On 2026-01-02, Michael Sanders <porkchop@invalid.foo> wrote:
> 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.

Because you teleported here from 1985.

Pre-ANSI "classic" C didn't have "void". It was invented in C++ in the 1980s.

In classic C, if you didn't want a function to return anything,
you just omitted the type specifier for the function definition:

  foo() { }

The function's type was still "function returning int".  You had the of
the function would avoid trying to use the return value, and then
omitted returning one in the function. It was a "gentlemen's agreement"
for simulating procedures using functions.

This did not sit well with C++. C++ people wanted this gentlemen's
agreement codified properly into the type system, while remaining C
compatible. So the they introduced the void type and keyword.

Once void was a type specifier keyword in C++, then of course that
allowed declarators to create derived types, leading to the discovery
of "void *" (pointer to void). C++ decided to use it as a generic
pointer to any object, with the rule that other pointer-to-object
types could implicitly convert to void *, but not vice versa.

The ANSI C committe adopted void from C++, probably not just for
compatibility but because it jived with the stronger typing they
were introducing, including prototypes. (Also basically from C++?)

I seem to recall it was ANSI C that invented the syntactic hack of
(void) as a parameter list, because the () parameter list in C
meant "nothing is specified about the parameters" and that had to remain
for compatibility. So the (void) parameter list was adopted as denoting
"this function takes no parameters".

That hack was then adopted back into C++. In C++, () already meant
"this function is prototyped as having no parameters", but for
compatibility with ANSI C prototypes, C++ adopted (void) as a synonym
for that.

We have now gone full circle. () in C now means the same thing as in
C++, and (void) is now a historic quirk, required only for compatibility
with existing code and all the historic dialects which required it.

ANSI C adopted "void *" from C++ also, but in a slightly different
way, allowing implicit conversion botrh ways between pointer-to-object
types and pointer to void.

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

It is not typeless; it is a pointer to the type void.  void is an object
type, but incomplete; in that it is similar to something like "struct
foo" in the absence of another declaration that completes the foo struct
type.

Incomplete types cannot be used to access an object,
nor to define an object.

Since no object can be of type void, we know that a given void *, if it
points to an object, does not have that object's correct type.
It only has the correct address.

The void * type, along with the "{signed | unsigned | <nothing> } char *" type,
is "blessed" by the language standard as being able to represent the
address of any object: a pointer to any object type can be converted to
void * such that it can then be converted back to that original type,
recovering the original pointer.

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

That's right; and if that's the only pointer type we have, then
we have a problem: we cannot write a function like memcpy
for copying any type of object. I mean, we cannot even write its
prototype.

There are ways around it with complicated mechanisms for generics,
like C++ templates.

One way to achieve generic code in the middle of a static type system is
to have escape hatches to get around the type system, at the cost of
safety.

Safety is the property of the language assuring correct operation
by rejecting incorrect situations in programs (either prior to run time
or at least at run time).

When we abandon safety, then assuring correct operation is left
to the programmer; the language translator or run-time is not required
to identify and reject incorrect situations.

With void pointers, we can create a data type such as a linked list
containing any objects (by reference) and even integers (by conversion
to void * and back).

The nodes of the list are declared as having an member of type "void *",
which holds the element datum.

The program must ensure that whatever values are stored into the list,
they are converted back to the original type when they are accessed.

This is not safe; it is possible to have a mistake whereby a list
of Widget objects made int he Widget module is accidentally passed
into a function in the Gadget module which requires a list of Gadget
objects.  That function retrieves the void * element values,
converts them to Gadget * and "hilarity ensues".

But, if you can avoid this kind of mistake, it is a very
easy-to-understand mechanism for generic programming, requiring
uncomplicated language support, and doesn't require all safety to be
abandoned.

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

It survives the lack of tracking the original type.

Nothing undefdined has happened so far, because genericPointer is
required to be capable of representing the address given by the
pointer-to-object type it is being initialized with.

Furthermore, you cannot use genericPointer directly to access anything.

You can't say "*genericPointer = 42.0" such that a string is clobbered
with a floating-point representation.

Where you leave type safety is when you do this:

  double *doublePtr = genericPointer;

Now you can do *doublePtr = 42.0.

> 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 has multiple semantics loaded onto it:

- Empty parameter list (ANSI C origin): (void)
- Function returning no value: void fn(...)
- Value of expression discarded by cast to void: (void) expr
- Pointer to any object: void *

These are all different and best regarded as unrelated.
Just like "static" has multiple meanings.

For instance, in a function returhning no value, you cannot
return a void value!

  void fn(void)
  {
    return (void) 42;
  }

Even though at first glance it appears that the type of the expression
"(void) 42" is compatible with the return type of void, that's not
how it works. The function returns nothing, and that nothing has no
type at all. In a function returning nothing, it is a diagnosable
constraint violation to have a return statement with an expression.
Only "return;" may appear.

Basically the language (or languages: both C and C++, in all their
current and historic dialects) play a game with void. There is a void
keyword and a void type, and the semantics is crafted to fit certain
contextual situations, in utilitarian ways.

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

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


#396092

FromKaz Kylheku <046-301-5902@kylheku.com>
Date2026-01-02 21:52 +0000
Message-ID<10j9enb$p6ts$2@dont-email.me>
In reply to#396084
On 2026-01-02, Michael Sanders <porkchop@invalid.foo> wrote:
> 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.

Because you teleported here from 1985.

Pre-ANSI "classic" C didn't have "void". It was invented in C++ in the 1980s.

In classic C, if you didn't want a function to return anything,
you just omitted the type specifier for the function definition:

  foo() { }

The function's type was still "function returning int".  You had the of
the function would avoid trying to use the return value, and then
omitted returning one in the function. It was a "gentlemen's agreement"
for simulating procedures using functions.

This did not sit well with C++. C++ people wanted this gentlemen's
agreement codified properly into the type system, while remaining C
compatible. So the they introduced the void type and keyword.

Once void was a type specifier keyword in C++, then of course that
allowed declarators to create derived types, leading to the discovery
of "void *" (pointer to void). C++ decided to use it as a generic
pointer to any object, with the rule that other pointer-to-object
types could implicitly convert to void *, but not vice versa.

The ANSI C committe adopted void from C++, probably not just for
compatibility but because it jived with the stronger typing they
were introducing, including prototypes. (Also basically from C++?)

I seem to recall it was ANSI C that invented the syntactic hack of
(void) as a parameter list, because the () parameter list in C
meant "nothing is specified about the parameters" and that had to remain
for compatibility. So the (void) parameter list was adopted as denoting
"this function takes no parameters".

That hack was then adopted back into C++. In C++, () already meant
"this function is prototyped as having no parameters", but for
compatibility with ANSI C prototypes, C++ adopted (void) as a synonym
for that.

We have now gone full circle. () in C now means the same thing as in
C++, and (void) is now a historic quirk, required only for compatibility
with existing code and all the historic dialects which required it.

ANSI C adopted "void *" from C++ also, but in a slightly different
way, allowing implicit conversion botrh ways between pointer-to-object
types and pointer to void.

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

It is not typeless; it is a pointer to the type void.  void is an object
type, but incomplete; in that it is similar to something like "struct
foo" in the absence of another declaration that completes the foo struct
type.

Incomplete types cannot be used to access an object,
nor to define an object.

Since no object can be of type void, we know that a given void *, if it
points to an object, does not have that object's correct type.
It only has the correct address.

The void * type, along with the "{signed | unsigned | <nothing> } char *" type,
is "blessed" by the language standard as being able to represent the
address of any object: a pointer to any object type can be converted to
void * such that it can then be converted back to that original type,
recovering the original pointer.

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

That's right; and if that's the only pointer type we have, then
we have a problem: we cannot write a function like memcpy
for copying any type of object. I mean, we cannot even write its
prototype.

There are ways around it with complicated mechanisms for generics,
like C++ templates.

One way to achieve generic code in the middle of a static type system is
to have escape hatches to get around the type system, at the cost of
safety.

Safety is the property of the language assuring correct operation
by rejecting incorrect situations in programs (either prior to run time
or at least at run time).

When we abandon safety, then assuring correct operation is left
to the programmer; the language translator or run-time is not required
to identify and reject incorrect situations.

With void pointers, we can create a data type such as a linked list
containing any objects (by reference) and even integers (by conversion
to void * and back).

The nodes of the list are declared as having an member of type "void *",
which holds the element datum.

The program must ensure that whatever values are stored into the list,
they are converted back to the original type when they are accessed.

This is not safe; it is possible to have a mistake whereby a list
of Widget objects made int he Widget module is accidentally passed
into a function in the Gadget module which requires a list of Gadget
objects.  That function retrieves the void * element values,
converts them to Gadget * and "hilarity ensues".

But, if you can avoid this kind of mistake, it is a very
easy-to-understand mechanism for generic programming, requiring
uncomplicated language support, and doesn't require all safety to be
abandoned.

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

It survives the lack of tracking the original type.

Nothing undefdined has happened so far, because genericPointer is
required to be capable of representing the address given by the
pointer-to-object type it is being initialized with.

Furthermore, you cannot use genericPointer directly to access anything.

You can't say "*genericPointer = 42.0" such that a string is clobbered
with a floating-point representation.

Where you leave type safety is when you do this:

  double *doublePtr = genericPointer;

Now you can do *doublePtr = 42.0.

> 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 has multiple semantics loaded onto it:

- Empty parameter list (ANSI C origin): (void)
- Function returning no value: void fn(...)
- Value of expression discarded by cast to void: (void) expr
- Pointer to any object: void *

These are all different and best regarded as unrelated.
Just like "static" has multiple meanings.

For instance, in a function returhning no value, you cannot
return a void value!

  void fn(void)
  {
    return (void) 42;
  }

Even though at first glance it appears that the type of the expression
"(void) 42" is compatible with the return type of void, that's not
how it works. The function returns nothing, and that nothing has no
type at all. In a function returning nothing, it is a diagnosable
constraint violation to have a return statement with an expression.
Only "return;" may appear.

Basically the language (or languages: both C and C++, in all their
current and historic dialects) play a game with void. There is a void
keyword and a void type, and the semantics is crafted to fit certain
contextual situations, in utilitarian ways.

It's like certain words in English, like prepositions.

Sometimes "by" means next to, like "stand by me".

Sometimes it denotes agency: "pass by value".

Sometimes an upper temporal limit: "by the time you get there".

If you're a learner of the language and all you know so far is the "by"
of "stand by me", you are confused by "by the same time tomorrow".

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

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


#396093

From"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com>
Date2026-01-02 14:18 -0800
Message-ID<10j9g71$pr9o$1@dont-email.me>
In reply to#396092
On 1/2/2026 1:52 PM, Kaz Kylheku wrote:
> On 2026-01-02, Michael Sanders <porkchop@invalid.foo> wrote:
>> 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.
> 
> Because you teleported here from 1985.

[...]

One note, void* cannot hold a function pointer without getting undefined 
or implementation-defined behavior.

typedef void (*generic_func_ptr)(void)

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


#396106

FromDavid Brown <david.brown@hesbynett.no>
Date2026-01-03 13:55 +0100
Message-ID<10jb3j5$17gcb$3@dont-email.me>
In reply to#396093
On 02/01/2026 23:18, Chris M. Thomasson wrote:
> On 1/2/2026 1:52 PM, Kaz Kylheku wrote:
>> On 2026-01-02, Michael Sanders <porkchop@invalid.foo> wrote:
>>> 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.
>>
>> Because you teleported here from 1985.
> 
> [...]
> 
> One note, void* cannot hold a function pointer without getting undefined 
> or implementation-defined behavior.
> 

Kaz mentioned several types that "void *" is a generic /object/ pointer. 
  Functions are not objects - pointers to functions are completely 
different from pointers to objects.  You can't mix them without "I know 
what I am doing" explicit casts, with non-portable behaviour and a 
serious risk of UB.

> typedef void (*generic_func_ptr)(void)

There is no generic function pointer type equivalent to "void *" - you 
are always going to need casts when converting between different pointer 
types.  And you /really/ need to make sure you convert to exactly the 
correct type before calling the pointed-to function.  But the definition 
you gave here is commonly used when people want to have generic function 
pointers.

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


#396117

From"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com>
Date2026-01-03 12:04 -0800
Message-ID<10jbsp0$1gf7e$1@dont-email.me>
In reply to#396106
On 1/3/2026 4:55 AM, David Brown wrote:
> On 02/01/2026 23:18, Chris M. Thomasson wrote:
>> On 1/2/2026 1:52 PM, Kaz Kylheku wrote:
>>> On 2026-01-02, Michael Sanders <porkchop@invalid.foo> wrote:
>>>> 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.
>>>
>>> Because you teleported here from 1985.
>>
>> [...]
>>
>> One note, void* cannot hold a function pointer without getting 
>> undefined or implementation-defined behavior.
>>
> 
> Kaz mentioned several types that "void *" is a generic /object/ pointer. 

Oh, I missed that. Sorry everybody.


>   Functions are not objects - pointers to functions are completely 
> different from pointers to objects.  You can't mix them without "I know 
> what I am doing" explicit casts, with non-portable behaviour and a 
> serious risk of UB.

Indeed.


>> typedef void (*generic_func_ptr)(void)
> 
> There is no generic function pointer type equivalent to "void *" - you 
> are always going to need casts when converting between different pointer 
> types.  And you /really/ need to make sure you convert to exactly the 
> correct type before calling the pointed-to function.  But the definition 
> you gave here is commonly used when people want to have generic function 
> pointers.
> 

Agreed. Fwiw, here is some of my old code exploring some related things:


/* Interfaces
____________________________________________________________________*/
#include <stddef.h>


struct object_prv_vtable {
   int (*fp_destroy) (void* const);
};


struct device_prv_vtable {
   int (*fp_read) (void* const, void*, size_t);
   int (*fp_write) (void* const, void const*, size_t);
};


struct device_vtable {
   struct object_prv_vtable const object;
   struct device_prv_vtable const device;
};


struct device {
   struct device_vtable const* vtable;
};


#define object_destroy(mp_self) ( \
   (mp_self)->vtable->object.fp_destroy((mp_self)) \
)


#define device_read(mp_self, mp_buf, mp_size) ( \
   (mp_self)->vtable->device.fp_read((mp_self), (mp_buf), (mp_size)) \
)


#define device_write(mp_self, mp_buf, mp_size) ( \
   (mp_self)->vtable->device.fp_write((mp_self), (mp_buf), (mp_size)) \
)






/* Sample Header (usb_drive.h)
____________________________________________________________________*/
#if ! defined(USB_HEADER_H)
#define USB_HEADER_H


extern int usb_drive_create(struct device** const);


#endif







/* Sample Impl (usb_drive.c)
____________________________________________________________________*/
/* #include "usb_drive.c" */
#include <stdio.h>
#include <stdlib.h>


struct usb_drive {
   struct device device;
   /* whatever */
};


static int usb_drive_object_destroy(void* const);
static int usb_drive_device_read(void* const, void*, size_t);
static int usb_drive_device_write(void* const, void const*, size_t);


static struct device_vtable const g_table = {
   { /* object */
     usb_drive_object_destroy
   },

   { /* device */
     usb_drive_device_read,
     usb_drive_device_write
   }
};


int usb_drive_create(
  struct device** const pself
) {
   struct usb_drive* const self = malloc(sizeof(*self));
   if (self) {
     self->device.vtable = &g_table;
     *pself = &self->device;
     return 0;
   }
   return -1;
}


int usb_drive_object_destroy(
  void* const self_
) {
   struct usb_drive* const self = self_;
   printf("usb_drive_object_destroy(%p)\n", (void*)self);
   free(self_);
   return 0;
}


int usb_drive_device_read(
  void* const self_,
  void* buf,
  size_t size
) {
   struct usb_drive* const self = self_;
   printf("usb_drive_device_read(%p, %p, %lu)\n",
     (void*)self, buf, (unsigned long)size);
   return 0;
}


int usb_drive_device_write(
  void* const self_,
  void const* buf,
  size_t size
) {
   struct usb_drive* const self = self_;
   printf("usb_drive_device_write(%p, %p, %lu)\n",
     (void*)self, buf, (unsigned long)size);
   return 0;
}







/* Sample Application
____________________________________________________________________*/
void read_write(
  struct device* const self
) {
   char buf[100];

   device_read(self, buf, 50);

   device_write(self, buf, 5);
}


int main(void) {
   struct device* a_device;

   if (! usb_drive_create(&a_device)) {
     read_write(a_device);

     object_destroy(a_device);
   }

   return 0;
}

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


#396118

FromAndrey Tarasevich <noone@noone.net>
Date2026-01-03 13:01 -0800
Message-ID<10jc02j$1hk1n$1@dont-email.me>
In reply to#396117
On Sat 1/3/2026 12:04 PM, Chris M. Thomasson wrote:
 > struct object_prv_vtable {
 >    int (*fp_destroy) (void* const);
 > };
And interesting piece of trivia about C function types and function type 
compatibility rules is that:

1. Top-level qualifiers on function parameters are preserved as part of 
function type. However, such top-level qualifiers are ignored when 
determining function type compatibility.

2a. Pre-C17: Top-level qualifiers on function return type are preserved 
as part of function type. They are NOT ignored when determining function 
type compatibility, i.e. they have to match exactly for the types to be 
compatible.

2b. Post-C17: Top-level qualifiers on function return type are not 
included into the function type. (Function type compatibility rules 
remain unchanged: they still formally require a match, but now it's moot.)

For example, the following intializations are valid

   int foo(const int);
   int bar(int);
   ...
   int (*pa)(int) = &foo;
   int (*pb)(const int) = &bar;

Note: they function types do not match in this case, yet they are 
compatible. And that's all that's needed.

Meanwhile, the following initializations are invalid in pre-C17 version 
of the language

   const int baz(void);
   int qux(void);
   ...
   int (*pc)(void) = &baz;
   const int (*pd)(void) = &qux;

They become valid in C17 and later.

(Interestingly enough, Clang keeps complaining about them even in 
`-std=c17` mode.)

-- 
Best regards,
Andrey

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


#396265

FromTim Rentsch <tr.17687@z991.linuxsc.com>
Date2026-01-07 07:35 -0800
Message-ID<86bjj5phai.fsf@linuxsc.com>
In reply to#396118
Andrey Tarasevich <noone@noone.net> writes:

> On Sat 1/3/2026 12:04 PM, Chris M. Thomasson wrote:
>
>> struct object_prv_vtable {
>>    int (*fp_destroy) (void* const);
>> };
>
> And interesting piece of trivia about C function types and function
> type compatibility rules is that:
>
> 1. Top-level qualifiers on function parameters are preserved as part
> of function type.

Not completely wrong but not exactly right either.

> However, such top-level qualifiers are ignored when
> determining function type compatibility.

It's easier to take the point of view that top-level qualifiers
for function parameters don't participate in the type of the
function as a whole.  Taking that view is easier to understand
and gives results that are indistinguishable from the actual
rules.

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


#396273

FromAndrey Tarasevich <noone@noone.net>
Date2026-01-07 08:17 -0800
Message-ID<10jm0ul$oq53$1@dont-email.me>
In reply to#396265
On Wed 1/7/2026 7:35 AM, Tim Rentsch wrote:
> Andrey Tarasevich <noone@noone.net> writes:
> 
>> On Sat 1/3/2026 12:04 PM, Chris M. Thomasson wrote:
>>
>>> struct object_prv_vtable {
>>>     int (*fp_destroy) (void* const);
>>> };
>>
>> And interesting piece of trivia about C function types and function
>> type compatibility rules is that:
>>
>> 1. Top-level qualifiers on function parameters are preserved as part
>> of function type.
> 
> Not completely wrong but not exactly right either.
> 
>> However, such top-level qualifiers are ignored when
>> determining function type compatibility.
> 
> It's easier to take the point of view that top-level qualifiers
> for function parameters don't participate in the type of the
> function as a whole.  Taking that view is easier to understand
> and gives results that are indistinguishable from the actual
> rules.

No, that's not entirely accurate.

The C17 modifications I mentioned in my previous post stems from DR#423

https://www.open-std.org/jtc1/sc22/wg14/www/docs/summary.htm#dr_423

which is related to how qualifications are treated under `_Generic`. 
`_Generic` operates on "exact match" basis not on "type compatibility" 
basis. Which is why such matters suddenly become important.

The DR itself is about qualifications on rvalues (another thing that 
"did not matter" previously), not about function parameters. But it is 
clear that it applies to our topic as well.

I have no time to research it further at the moment (will do it a bit 
later), but something tells me that `_Generic` is expected to "see" and 
distinguish the exact const-qualification of function parameters in 
function types. If so, it might be a "useless" feature, but still..

-- 
Best regards,
Andrey

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


#396274

FromAndrey Tarasevich <noone@noone.net>
Date2026-01-07 08:23 -0800
Message-ID<10jm1a1$pfer$1@dont-email.me>
In reply to#396273
On Wed 1/7/2026 8:17 AM, Andrey Tarasevich wrote:
> 
> which is related to how qualifications are treated under `_Generic`. 
> `_Generic` operates on "exact match" basis not on "type compatibility" 
> basis. Which is why such matters suddenly become important.
> 

No, I take it back. `_Generic` chooses its branches based on type 
compatibility.

In that case it raises an interesting question: why does the C standard 
keeps sticking to this, i.e. keeps persistent top-level qualifiers on 
function parameters? Why not switch to C++-like approach and just 
discard such qualifiers at the parameter type adjustment stage? 
Especially now, after C17 started to explicitly do this with the return 
type.

-- 
Best regards,
Andrey

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


#396291

FromTim Rentsch <tr.17687@z991.linuxsc.com>
Date2026-01-07 18:44 -0800
Message-ID<86ldi8ombu.fsf@linuxsc.com>
In reply to#396274
Andrey Tarasevich <noone@noone.net> writes:

> On Wed 1/7/2026 8:17 AM, Andrey Tarasevich wrote:
>
>> which is related to how qualifications are treated under
>> _Generic`. `_Generic` operates on "exact match" basis not on "type
>> compatibility" basis.  Which is why such matters suddenly become
>> important.
>
> No, I take it back.  `_Generic` chooses its branches based on type
> compatibility.

Right.  For _Generic, top-level qualifiers are dropped (IIUC).

Incidental comment:  the discussion in DR 423 leaves much to be
desired.

> In that case it raises an interesting question:  why does the C
> standard keeps sticking to this, i.e. keeps persistent top-level
> qualifiers on function parameters?  Why not switch to C++-like approach
> and just discard such qualifiers at the parameter type adjustment
> stage?  Especially now, after C17 started to explicitly do this with
> the return type.

My guess is that's a consequence of the processes used to write the
ISO C standard and to modify the ISO C standard.  A lot of work goes
into both writing the text initially and revising the text later when
a change is needed (talking about a change to the text, which could be
either a modification of an earlier semantics or a clarification of an
earlier semantics).  Sometimes there is a sense that a smaller change
would mean less work and also a smaller chance of unintended problems
(and errors), so a smaller change is chosen even though the end result
is less attractive.  Perhaps that happened here, in much the same way
that modifying source code might choose an easier path locally to the
detriment of some larger overall aesthetic.

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


#396290

FromTim Rentsch <tr.17687@z991.linuxsc.com>
Date2026-01-07 18:27 -0800
Message-ID<86pl7kon49.fsf@linuxsc.com>
In reply to#396273
Andrey Tarasevich <noone@noone.net> writes:

> On Wed 1/7/2026 7:35 AM, Tim Rentsch wrote:
>
>> Andrey Tarasevich <noone@noone.net> writes:
>>
>>> On Sat 1/3/2026 12:04 PM, Chris M. Thomasson wrote:
>>>
>>>> struct object_prv_vtable {
>>>>     int (*fp_destroy) (void* const);
>>>> };
>>>
>>> And interesting piece of trivia about C function types and function
>>> type compatibility rules is that:
>>>
>>> 1.  Top-level qualifiers on function parameters are preserved as part
>>> of function type.
>>
>> Not completely wrong but not exactly right either.
>>
>>> However, such top-level qualifiers are ignored when
>>> determining function type compatibility.
>>
>> It's easier to take the point of view that top-level qualifiers
>> for function parameters don't participate in the type of the
>> function as a whole.  Taking that view is easier to understand
>> and gives results that are indistinguishable from the actual
>> rules.
>
> No, that's not entirely accurate.
>
> The C17 modifications I mentioned in my previous post stems from DR#423
>
> https://www.open-std.org/jtc1/sc22/wg14/www/docs/summary.htm#dr_423
>
> which is related to how qualifications are treated under
> _Generic`. `_Generic` operates on "exact match" basis not on "type
> compatibility" basis.  Which is why such matters suddenly become
> important.
>
> The DR itself is about qualifications on rvalues (another thing that
> "did not matter" previously), not about function parameters.  But it is
> clear that it applies to our topic as well.
>
> I have no time to research it further at the moment (will do it a bit
> later), but something tells me that `_Generic` is expected to "see"
> and distinguish the exact const-qualification of function parameters
> in function types.  If so, it might be a "useless" feature, but still..

I see you have posted a further followup.  I am responding to
that.

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


#396121

FromLawrence D’Oliveiro <ldo@nz.invalid>
Date2026-01-03 22:05 +0000
Message-ID<10jc3qo$1i4ia$9@dont-email.me>
In reply to#396117
On Sat, 3 Jan 2026 12:04:47 -0800, Chris M. Thomasson wrote:

> struct object_prv_vtable {
>    int (*fp_destroy) (void* const);
> };
>
> ...
>
>    (mp_self)->vtable->object.fp_destroy((mp_self)) \

which is easier to write than

    (*(mp_self)->vtable->object.fp_destroy)((mp_self))

, don’t you think? (And similarly for other cases in that code.)

Look on it as a fudge allowed by C to get around the awkwardness of
its inside-out type definitions ...

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


#396130

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2026-01-03 16:39 -0800
Message-ID<875x9i43f1.fsf@example.invalid>
In reply to#396106
David Brown <david.brown@hesbynett.no> writes:
> On 02/01/2026 23:18, Chris M. Thomasson wrote:
[...]
>> typedef void (*generic_func_ptr)(void)
>
> There is no generic function pointer type equivalent to "void *" - you
> are always going to need casts when converting between different
> pointer types.  And you /really/ need to make sure you convert to
> exactly the correct type before calling the pointed-to function.  But
> the definition you gave here is commonly used when people want to have
> generic function pointers.

Yes, but ...

There is no generic function pointer type equivalent to void* in the
sense that values can be converted to and from the type implicitly.
For example:

    int n = 42;
    void *vp = &n;   // implicit conversion
    double *dp = vp; // implicit conversion, potentially dangerous

There are no such implicit conversions for function pointer types.

However, in the sense of a round-trip conversion yielding the
original result *all* function pointer types can be treated as
generic function pointer types.  You just have to use casts to do
any conversions.

It's very common for all pointer types in a given implementation
to have the same representation, and for round-trip conversions
to safely yield the original value, but it's not guaranteed by
the language, and there are implementations where, for example,
function pointer types are bigger than object pointer types, or
void* is bigger than int*.  Certain collections of pointer types
are guaranteed by the language to have the same representation:

- void*, char*, signed char*, unsigned char*
- All struct pointer types
- All union pointer types
- All function pointer types

Incidentally, if I want a generic function pointer type, I might
define it so that it can't be used accidentally without a cast.
For example:

    typedef struct dummy__ (generic_function)(void);

where struct dummy__ is an incomplete type.  (Note that I've
typedef'ed the function type, not the pointer type.)  But that
might be considered overkill; treating a void function with
no parameters as generic is probably good enough.

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


#396139

FromDavid Brown <david.brown@hesbynett.no>
Date2026-01-04 12:15 +0100
Message-ID<10jdi4h$1ui8e$2@dont-email.me>
In reply to#396130
On 04/01/2026 01:39, Keith Thompson wrote:
> David Brown <david.brown@hesbynett.no> writes:
>> On 02/01/2026 23:18, Chris M. Thomasson wrote:
> [...]
>>> typedef void (*generic_func_ptr)(void)
>>
>> There is no generic function pointer type equivalent to "void *" - you
>> are always going to need casts when converting between different
>> pointer types.  And you /really/ need to make sure you convert to
>> exactly the correct type before calling the pointed-to function.  But
>> the definition you gave here is commonly used when people want to have
>> generic function pointers.
> 
> Yes, but ...
> 
> There is no generic function pointer type equivalent to void* in the
> sense that values can be converted to and from the type implicitly.
> For example:
> 
>      int n = 42;
>      void *vp = &n;   // implicit conversion
>      double *dp = vp; // implicit conversion, potentially dangerous
> 
> There are no such implicit conversions for function pointer types.
> 

Yes.

> However, in the sense of a round-trip conversion yielding the
> original result *all* function pointer types can be treated as
> generic function pointer types.  You just have to use casts to do
> any conversions.
> 

Yes.  This also means there is no generic function pointer type 
equivalent to "void *" for object pointers, since there is no one 
function pointer type that stands out, no special case, and no common 
agreement on the type.  Some people will use "void (*)(void)", some will 
use "int (*)(int)", some "int (*)()", and so on.  That is another sense 
in which there is no function pointer type equivalent to "void *".

> It's very common for all pointer types in a given implementation
> to have the same representation, and for round-trip conversions
> to safely yield the original value, but it's not guaranteed by
> the language, and there are implementations where, for example,
> function pointer types are bigger than object pointer types, or
> void* is bigger than int*.  Certain collections of pointer types
> are guaranteed by the language to have the same representation:
> 
> - void*, char*, signed char*, unsigned char*
> - All struct pointer types
> - All union pointer types
> - All function pointer types
> 
> Incidentally, if I want a generic function pointer type, I might
> define it so that it can't be used accidentally without a cast.
> For example:
> 
>      typedef struct dummy__ (generic_function)(void);
> 
> where struct dummy__ is an incomplete type.  (Note that I've
> typedef'ed the function type, not the pointer type.)  But that
> might be considered overkill; treating a void function with
> no parameters as generic is probably good enough.
> 

The dummy struct idea is nice - it could help avoid accidents.

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


#396227

FromKaz Kylheku <046-301-5902@kylheku.com>
Date2026-01-06 20:33 +0000
Message-ID<20260106123319.105@kylheku.com>
In reply to#396106
On 2026-01-03, David Brown <david.brown@hesbynett.no> wrote:
> On 02/01/2026 23:18, Chris M. Thomasson wrote:
>> On 1/2/2026 1:52 PM, Kaz Kylheku wrote:
>>> On 2026-01-02, Michael Sanders <porkchop@invalid.foo> wrote:
>>>> 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.
>>>
>>> Because you teleported here from 1985.
>> 
>> [...]
>> 
>> One note, void* cannot hold a function pointer without getting undefined 
>> or implementation-defined behavior.
>> 
>
> Kaz mentioned several types that "void *" is a generic /object/ pointer. 
>   Functions are not objects - pointers to functions are completely 
> different from pointers to objects.  You can't mix them without "I know 
> what I am doing" explicit casts, with non-portable behaviour and a 
> serious risk of UB.

"I know that I'm on POSIX" goes a long way also.

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

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


#396238

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2026-01-06 17:01 -0800
Message-ID<87cy3m2q2z.fsf@example.invalid>
In reply to#396227
Kaz Kylheku <046-301-5902@kylheku.com> writes:
> On 2026-01-03, David Brown <david.brown@hesbynett.no> wrote:
[...]
>> Kaz mentioned several types that "void *" is a generic /object/ pointer. 
>>   Functions are not objects - pointers to functions are completely 
>> different from pointers to objects.  You can't mix them without "I know 
>> what I am doing" explicit casts, with non-portable behaviour and a 
>> serious risk of UB.
>
> "I know that I'm on POSIX" goes a long way also.

Sort of.

POSIX doesn't guarantee that all function pointers can be converted
to void* without loss of information.  It makes that guarantee only
for pointers returned by dlsym().

https://pubs.opengroup.org/onlinepubs/9799919799/functions/dlsym.html

On the other hand, I'd be surprised if there were any
POSIX-conforming implementation that don't make that guarantee for
all function pointers.  There are some tricks that could be played
to satisfy the dlsym() requirement even if function pointers are
bigger than void*, but I've never heard of an implementation that
did anything like that.

(For example, say the system has 64-bit function pointers and
32-bit void*.  The implementation could arrange for every function
referenced by dlsym() to have an address with its upper 32 bits set
to zero, perhaps by using small wrapper functions.  Other functions
might have arbitrary addresses so converting them to void* would
lose information.)

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


#396100

FromMichael Sanders <porkchop@invalid.foo>
Date2026-01-03 06:08 +0000
Message-ID<10jabp8$11n14$2@dont-email.me>
In reply to#396092
On Fri, 2 Jan 2026 21:52:43 -0000 (UTC), Kaz Kylheku wrote:

> Because you teleported here from 1985.

Get out of here Kaz. But seriously, thanks for the detailed
reply. I move forward day-by-day.

-- 
:wq
Mike Sanders

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


#396189

From"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com>
Date2026-01-05 12:40 -0800
Message-ID<10jh7j8$37pj1$1@nntp.eternal-september.org>
In reply to#396100
On 1/2/2026 10:08 PM, Michael Sanders wrote:
> On Fri, 2 Jan 2026 21:52:43 -0000 (UTC), Kaz Kylheku wrote:
> 
>> Because you teleported here from 1985.
> 
> Get out of here Kaz. 

Why? Kaz is a smart guy!


> But seriously, thanks for the detailed
> reply. I move forward day-by-day.
> 

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


#396199

FromMichael Sanders <porkchop@invalid.foo>
Date2026-01-06 04:30 +0000
Message-ID<10ji35u$3gdod$1@nntp.eternal-september.org>
In reply to#396189
On Mon, 5 Jan 2026 12:40:08 -0800, Chris M. Thomasson wrote:

> On 1/2/2026 10:08 PM, Michael Sanders wrote:
>> On Fri, 2 Jan 2026 21:52:43 -0000 (UTC), Kaz Kylheku wrote:
>> 
>>> Because you teleported here from 1985.
>> 
>> Get out of here Kaz. 
> 
> Why? Kaz is a smart guy!

I'm teasing Kaz. I know him from other haunts.
A sharp guy - its all good.


-- 
:wq
Mike Sanders

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


#396239

From"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com>
Date2026-01-06 17:05 -0800
Message-ID<10jkbh9$9e57$4@dont-email.me>
In reply to#396199
On 1/5/2026 8:30 PM, Michael Sanders wrote:
> On Mon, 5 Jan 2026 12:40:08 -0800, Chris M. Thomasson wrote:
> 
>> On 1/2/2026 10:08 PM, Michael Sanders wrote:
>>> On Fri, 2 Jan 2026 21:52:43 -0000 (UTC), Kaz Kylheku wrote:
>>>
>>>> Because you teleported here from 1985.
>>>
>>> Get out of here Kaz.
>>
>> Why? Kaz is a smart guy!
> 
> I'm teasing Kaz. I know him from other haunts.
> A sharp guy - its all good.
> 
> 

:^)

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


Page 2 of 4 — ← Prev page 1 [2] 3 4  Next page →

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


csiph-web