home bbs files messages ]

Forums before death by AOL, social media and spammers... "We can't have nice things"

   comp.lang.c      Meh, in C you gotta define EVERYTHING      243,242 messages   

[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]

   Message 242,713 of 243,242   
   Kaz Kylheku to Michael Sanders   
   Re: function pointer question (1/2)   
   02 Jan 26 21:50:06   
   
   From: 046-301-5902@kylheku.com   
      
   On 2026-01-02, Michael Sanders  wrote:   
   > On Fri, 2 Jan 2026 17:48:16 -0000 (UTC), Kaz Kylheku wrote:   
   >   
   >> On 2026-01-02, Michael Sanders  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 |  } 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(...)   
      
   [continued in next message]   
      
   --- SoupGate-Win32 v1.05   
    * Origin: you cannot sedate... all the things you hate (1:229/2)   

[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]


(c) 1994,  bbs@darkrealms.ca