[HN Gopher] Polymorphic Types in C [pdf]
       ___________________________________________________________________
        
       Polymorphic Types in C [pdf]
        
       Author : sigsev_251
       Score  : 92 points
       Date   : 2024-01-15 10:02 UTC (3 days ago)
        
 (HTM) web link (open-std.org)
 (TXT) w3m dump (open-std.org)
        
       | vkazanov wrote:
       | Wow, suggesting polymorphic types to WG14 is... brave!
        
       | illegalmemory wrote:
       | I had worked on something similar around 11-12 years back ( no
       | way close to perfect or of any use :) )
       | https://github.com/nautical/CBullet
       | 
       | Basically you can do something like this in c :
       | 
       | var value;
       | 
       | value = data(100);
       | 
       | // or
       | 
       | value = data(0, 2, 3, 4, 5, 6);
        
       | pjmlp wrote:
       | The answer to most post-C89 features could be just use C++, but
       | yeah, changing human nature is a lost fight.
        
         | j16sdiz wrote:
         | C++ is somewhat bloat.
         | 
         | We need a "C++ lite".
         | 
         | We do this by moving features from C++ to C, bit-by-bits, until
         | C become bloated.
        
           | pjmlp wrote:
           | C would do better improving what matters, the lack of safe
           | enumerations, strings and arrays, but even that they fail to
           | copy from C++.
        
             | lebubule wrote:
             | Yes, please better support for arrays, mainly
             | multidimensional. Fortran is good for that. With good
             | arrays I think that strings comes naturally.
        
               | uecker wrote:
               | What is wrong with multi-dimensional arrays in C? It
               | works far better than in C++:
               | 
               | void foo(int X, int Y) { double a[X][Y]; .. }
               | 
               | In fact, this is one reason I switched away from C++,
               | because arrays are so bad in C++.
        
               | pjmlp wrote:
               | That is a CVE waiting to be exploited.
        
               | uecker wrote:
               | No.
        
               | pjmlp wrote:
               | It definitely is, given a nice combination of parameter
               | values, stack sizes and careless programming.
        
           | abcd_f wrote:
           | > _somewhat_ bloat
           | 
           | ... is somewhat understatement.
        
           | logicprog wrote:
           | It's really frustrating to watch this happen, first with
           | using arrays to mean non void pointers, then with _Generic
           | for dispatching on types, and now this. And the worst part to
           | me is not necessarily that they're complicating or "bloating"
           | C, because these _are_ necessary features, the worst part to
           | me is that they seem to simultaneously recognize these
           | features are necessary, and not want to commit to a full and
           | proper implementation of them like e.g. proper generics or
           | simple templates. Instead they create stuff like this, where
           | they haven 't fully committed and so it's weird and awkward
           | to use and doesn't feel fully integrated into the language,
           | with less clear semantics, so in the end it ends up kind of
           | _worse_ than C++, whereas what I wish they 'd do, if they're
           | going to bring features from C++ to C, is just fully and
           | properly _implement the feature_ , but make it as simple and
           | limited and basic as possible -- the basic concept of
           | templates and monomorphization makes sense to me, buy I'm not
           | exactly sure how this works at compile time.
           | 
           | It this point, if I want generics, I'd rather just use C++.
        
             | uecker wrote:
             | Note that a type system with polymorphic and dependent type
             | system is far more powerful than generics or simple
             | templates. In my opinion monomorphization is rather bad,
             | because it creates a lot of compile time bloat while still
             | not being very expressive from a type system point of view.
        
         | vkazanov wrote:
         | Many in this industry dislike C++'s approach to language
         | design: "let's add everything and see what sticks".
        
           | pjmlp wrote:
           | C is just the same, it just happens that not many people feel
           | like showing up on WG14 meetings and push for their
           | proposals.
           | 
           | Showing up at WG21 is much more appealing to most folks.
           | 
           | Maybe compare how C23 compares to C89, and future roadmap.
        
             | flohofwoe wrote:
             | > Showing up at WG21 is much more appealing to most folks.
             | 
             | ...and let's just hope it stays that way ;)
        
         | flohofwoe wrote:
         | C++ has added more new design warts on top of C than C ever had
         | though (which means that C++ is now caught in an infinite cycle
         | of trying to fix warts it had introduced itself a couple of
         | years ago).
         | 
         | At least in C there's a possibility to learn from C++'s
         | mistakes, and only integrate the 'good parts' (and the C++
         | template system certainly isn't one of those good parts).
        
           | pjmlp wrote:
           | Unfortunely doesn't look like it is happening any time soon.
        
           | logicprog wrote:
           | Yeah, that would be the ideal -- take just the simplest,
           | cleanest version of C++'s good parts and integrated them. But
           | lile the sibling post said, that's not what they're doing.
           | Instead they're designing their own new versions of each
           | feature that they add, and because it seems they're not
           | willing to fully commit to new features or changing the
           | language much, the features are always _weirder_ with _more_
           | gotchas and _less_ baked than thr C++ versions. It isn 't so
           | bad right now because the language is overall much smaller,
           | but if they eventually grow to anything close to the size of
           | C++ (and C++ isn't even that big of a language anymore
           | compared to other modern languages) it'll actually be way
           | worse.
        
             | uecker wrote:
             | Having switched from C++ to C, I think C is a lot less
             | weird than C++. But I also observed that C++ programmers
             | usually do not "get" C (but think they do, because "it is
             | just a subset") and often think some parts are weird simply
             | because they are different.
             | 
             | In any case, if you need a clean subset of C++ (but nobody
             | I have met really agreed about what this is) nobody is
             | stopping you from defining one.
        
               | logicprog wrote:
               | > Having switched from C++ to C, I think C is a lot less
               | weird than C++.
               | 
               | Overall? Without a doubt. But these specific features
               | they've been adding are implemented very unnecessarily
               | strangely just to avoid fully committing to them, so that
               | they end up in this design space where they may not be
               | weirder than the full Lovecraftian horror of the
               | equivalent C++ feature, but they are much weirder than
               | the ideal/abstract concept of the equivalent C++ feature,
               | which is what I wish they would have pulled in. Like,
               | looking at this proposal, it isn't clear to me at all how
               | the compiler is actually compiling or the runtime is
               | executing these polymorphic function calls at all, in
               | cases where they don't just collapse to void*. And it
               | isn't clear to me how exactly type scoping and
               | substitution works either. Whereas in concept at least
               | templates are crystal clear and also easy to expand to do
               | much more advanced macro-less metaprogramming, like D
               | does.
               | 
               | > and often think some parts are weird simply because
               | they are different.
               | 
               | I have way more experience with C than C++, but I'm
               | usually a Rust programmer which works more like C++ so
               | maybe that's where my bias is, but I really think this
               | implementation is unnecessarily weird in general too --
               | I've used a lot of languages.
        
           | phkahler wrote:
           | >> At least in C there's a possibility to learn from C++'s
           | mistakes, and only integrate the 'good parts
           | 
           | That's what Rust looked like in the beginning - a better C++.
           | But that seems to be getting corrupted by a bunch of language
           | designers too now.
        
             | sigsev_251 wrote:
             | Curious, why do you think Rust does not look like a better
             | C++ (in the sense of not making the mistakes of it)? Is
             | there something you find impractical?
        
               | phkahler wrote:
               | It still does look like a better C++, but I think it's
               | being extended way too fast and might suffer the same
               | shitificantion if they don't stop it.
        
               | logicprog wrote:
               | Yeah, I'm a huge Rust fan, but some of the decisions
               | they've been making with the newer RFCs, especially
               | around things like convenience syntax, and the fact that
               | they now have async/await _and_ neutered coroutines,
               | instead of having proper coroutines capable of doing both
               | ala Kotlin, among other things, seem really iffy to me. I
               | 'm afraid it'll turn into Scala or something soon, with a
               | huge bag of redundant or partially overlapping features.
        
         | crabbone wrote:
         | I've been somewhat successful to use Ada instead. It has a lot
         | of inconveniences of its own, but compared to C++ it's a
         | language where it's hard to get things to work in any way, but
         | once you get them to work, they are likely to do what you want,
         | whereas in C++ it's easy to get things to compile, but then
         | heaven only knows what that code will do.
         | 
         | Also, Ada has a very decent interop with C. To the point that
         | w/o any prior experience, I needed to use some functions from
         | SQLite that weren't already exposed through Ada, and it was a
         | pretty smooth sailing: very little "glue" code, all code that
         | connected C and Ada was written in Ada.
        
           | pjmlp wrote:
           | Ada would be even better, unfortunely it is tainted by its
           | past, and not an easy sell for most folks.
        
         | tonyedgecombe wrote:
         | My guess is this is what most people do. The few remaining
         | holdouts are busy turning C into something that isn't C because
         | they don't like things that aren't C.
        
         | kitd wrote:
         | There's libcello if you want to stay in C
         | 
         | https://www.libcello.org/
        
           | synergy20 wrote:
           | which is inactive and the author has no intention to evolve
           | it I think
        
         | flykespice wrote:
         | What about Ziglang?
        
           | pjmlp wrote:
           | In a way, Zig to me is Modula-2 with a revamped syntax for C
           | minded folks, with a nice meta-programming story. In terms of
           | language features.
           | 
           | Personally I am not a big fan, because it doesn't have a good
           | story for use-after-free (other than adopting similar
           | analyser tooling like C derived languages), if I want to type
           | @ all over the place I can use Objective-C, and the community
           | doesn't seem very keen in supporting binary library
           | distribution.
           | 
           | That is me, we don't have to like all the same things.
           | 
           | Even with UAF caveat, it still better than plain old C.
           | 
           | Personally I find Odin more appealing than Zig.
        
         | vbtemp wrote:
         | I wish I had more than one upvote to give - what you just wrote
         | is the truth of the matter.
        
       | pgen wrote:
       | Great, but I hate these leading underscores.
        
         | injuly wrote:
         | It's for backwards compatibility of C compilers (and lack of
         | proper namespaces). All identifiers starting with an underscore
         | are reserved for use by compiler intrinsics and such. Although
         | most compilers don't complain if your variable names start with
         | a leading underscore, it is recommended to not have such
         | identifiers in your code.
        
         | vkazanov wrote:
         | They will probably come with macro-based aliases, the same way
         | they did it elsewhere.
        
         | Gibbon1 wrote:
         | I feel increasingly annoyed with the idea that C can never have
         | new keywords. As if that's some sort of huge problem with
         | existing code bases.
        
         | flohofwoe wrote:
         | This is so that the new keywords don't collide with existing
         | code (the combination of underscore followed by a capital
         | letter is reserved). For instance until C23, 'bool' was
         | actually called '_Bool' internally.
         | 
         | Just as with stdbool.h before, there could be a stdlib header
         | which wraps those internal names into something more human-
         | friendly.
        
         | uecker wrote:
         | Me too.
        
       | injuly wrote:
       | Polymorphic types are certainly useful, and I wish C had a better
       | way to go about it, but this proposal feels like an odd patch to
       | C's type system. Especially this part:
       | 
       | ``` Using a run-time value of type _Type T in _Var(T) can be
       | allowed in general (and is useful), but needs to be restricted to
       | contexts where full type information is not required at compile-
       | time. ```
       | 
       | Semantic rules that conditionally apply only in some contexts is
       | a common tendency of the C++ standard that many C programmers
       | often dislike.
        
         | nxobject wrote:
         | Here is another way in which this is a little patch-like. The
         | author observes that:
         | 
         | (a) it is desired that _Var(T)* and void* be compatible;
         | 
         | (b) however. pointers-to-T for different T are not guaranteed
         | to be compatible in general,
         | 
         | as a consequence, it is NOT guaranteed that _Var(T)* is
         | compatible with T*, which is a theoretical wart worthy of C++.
         | I can see it becoming especially annoying if you're trying to
         | introduce _Var(T) polymorphism into a code base that currently
         | uses preprocessor macros that textually substitute types.
         | 
         | Perhaps the better solution would be forgo giving void* any
         | special status whatsoever. However, that means that this type
         | of polymorphism can't be implemented using void* as a polyfill.
        
         | uecker wrote:
         | I don't think this is a deficiency, but an inherent property of
         | powerful type systems. If you make them very expressive, then
         | you can not have full type checking at compile time. On the
         | other hand, if you restrict them so that you do full static
         | type checking, than they are very limited.
        
       | lerno wrote:
       | The `any*` fat pointer in C3 is a version of this:
       | https://c3-lang.org/anyinterfaces/ Once this is available the
       | step to embedding some runtime type information isn't far.
        
         | eps wrote:
         | Clean, very nice.
        
         | eddd-ddde wrote:
         | I did not know about C3. I love C because is what I first learn
         | to program, the simplicity, the complete lack of magic. Looks
         | like I will love C3 as well:
         | 
         | > Avoid "big ideas".
        
         | keyle wrote:
         | Interesting. And reading all the changes from C, it looks like
         | what occasional C developers should always remind themselves
         | when coming back to C. That's a useful list by itself.
        
       | eps wrote:
       | As a (not so) minor point -
       | 
       | It's worth keeping in mind that code aesthetics is an important
       | aspect of C codebases. There's a lot of C code that is
       | exclusively lowercase, sans the macros. So introducing keywords
       | like _Type and _Var will serve to hinder their adoption, because
       | it'd make the code that much more "ugly". Just like what happened
       | with _Generic - a reasonable feature, bad keyword selection ->
       | barely any field use.
        
         | isomorphic- wrote:
         | The C specification mandates that new keywords use _Keyword
         | naming conventions to ensure backwards compatability by not
         | overriding potentially existing identifiers in codebases. That
         | is why the C specification has reserved identifiers that begin
         | with an underscore and either an uppercase letter or another
         | underscore.
         | 
         | Typically, a <stdkeyword.h> header is included that contain
         | macros to provide the lowercased variants. I.E., this is how
         | _Bool was implemented; <stdbool.h> provides the lowercased
         | `bool` variant.
        
           | eps wrote:
           | C23 is scheduled to promote bool, alignof & co. to keywords,
           | so the concern for using _Xxx keywords is recognized by the
           | committee. They introduce _Xxx keywords, sometimes alias them
           | to lowercase versions with macros and let this age. Then,
           | some time after, they switch to the "primary spelling", which
           | is how the lowercase versions are referred to.
           | 
           | You can't easily lowercase _Type and _Var, so practically
           | speaking it will take years before these features could be
           | suitable for wide-spread adoption. Hence my original comment
           | - given the friction, is it worth expanding the language this
           | way at all then?
        
             | lifthrasiir wrote:
             | _Bool etc. came with convenience macros defined from
             | <stdbool.h> and so on, but _Generic never did, suggesting
             | that the underscored version was meant to stay forever that
             | way. (Otherwise it should have been named as something like
             | _Generic_switch and later renamed to generic_switch...)
             | Maybe _Type and _Var are similarily intended.
        
               | sigsev_251 wrote:
               | I mean, _Generic is usually hidden behind a macro
               | anyways, so it doesn't really show up in you text file
               | all that much.
        
       | Dwedit wrote:
       | You can still use virtual function calls in plain C, you just do
       | things the same way that C++ does things internally. Your first
       | member of the struct is a Vtable, and you need to assign that
       | member when you create the object. Your first parameter for the
       | virtual method calls is a "this" pointer.
        
         | binary132 wrote:
         | Slight detail: there only needs to be one instance of the
         | vtable per class, and objects of that type only need to contain
         | a pointer to it.
        
           | Dwedit wrote:
           | And you can also make the vtable `const` so it goes into the
           | read-only data section.
        
         | huhtenberg wrote:
         | By the same argument we don't really need C to begin with,
         | because things can still be coded in assembly. It all boils
         | down to convenience of reducing boilerplate. As the meme goes -
         | "You don't need sneakers to run, but they sure help."
        
           | phkahler wrote:
           | And if I understand your point its that we should embrace
           | higher level tools rather than trying to build abstractions
           | in lower level tools. In that case OP should just use C++
           | rather than trying to build an abstraction into C. That going
           | higher level is actually why C++ was created in the first
           | place.
        
             | huhtenberg wrote:
             | The point was that if there's a certain coding pattern that
             | can be accommodated by adding a new language feature, it is
             | worth considering. The fact that it's readily doable with
             | some effort in some other way is not an argument against
             | it.
             | 
             | C++ started as a reasonable extension to C, but now it's
             | just something else (nor does it even want to be seen
             | related to C now anyway). Extending C with something new,
             | without rushing, is a perfectly fine idea.
        
         | o11c wrote:
         | The problem with rolling your own virtual tables without
         | compiler support is that devirtualization is generally not
         | possible, even in fairly easy cases.
        
         | brcmthrowaway wrote:
         | Isn't this GObject?
        
       | smcameron wrote:
       | Is it just me, or are disillusioned C++ refugees who've gone back
       | to C now trying to wreck it a second time? Probably just me.
       | Since the 80's, C++ served as an excellent decoy to absorb
       | craziness and keep C sane.
        
         | zabzonk wrote:
         | it is just you. why would anyone go back to C from C++? if you
         | want to write C in C++, you can do that, with the advantages of
         | stronger type checking.
        
           | SV_BubbleTime wrote:
           | You can use the C syntax in C++. But you are not using C,
           | your compiler is still C++.
        
             | zabzonk wrote:
             | yes the compiler is the same (for example gcc or msc) but
             | why would you care?
        
           | burstmode wrote:
           | Many people, Especially sice C++ has become a playfield for
           | CS language theorists, who invent more and more
           | overcomplicated language "features" with little to no
           | practical use.
        
             | pjmlp wrote:
             | That is still Haskell.
             | 
             | Getting features into WG21 still requires some effort to
             | get them through, regardless of what people in the outside
             | think, and yeah I do agree it could get some more
             | direction.
             | 
             | C++ may seem to get everything dumpped into it, however any
             | language nerd that feels like diving into what the history
             | of languages with similar age (Python, Perl, Ada, C#, Java,
             | F#, OCaml,...) have across all their versions, standard
             | library, main interpreter/compilers, .... will find out
             | those aren't much better either.
        
             | zabzonk wrote:
             | nobody makes you use these features, but when or if you
             | come to writing a library, you may well find them useful.
        
           | uecker wrote:
           | I switched back to C from C++. The reasons were that C
           | removes a lot of unnecessary complexity which helps
           | concentrating at the problem at hand. It also removes a lot
           | of features that when used incorrectly makes the code much
           | harder to understand. So if one often has to work with code
           | written by unexperienced programmers (as I have to do), I
           | found C++ very problematic. The stronger type checking is
           | largely a myth.
        
             | chlorion wrote:
             | It's definitely not a myth.
             | 
             | A trivial example is assigning pointers to incompatible
             | types or passing them to incompatible function parameters
             | not being an error. GCC 14 and Clang 16 are only just now
             | making these errors by default. C++ never had this problem.
             | 
             | Another example, is having type safe generic functions and
             | classes. Using void* to pass around arbitrary types is
             | something that you don't need to do in C++ because it
             | supports generic programming.
             | 
             | In C++ you can for example, pass an array of a specific
             | length to a function, and make it a compile time error to
             | pass an array of incorrect length, using std::array. In C
             | arrays decay to pointers.
             | 
             | static_case is also a thing in C++ that allows you to cast
             | between types much more safely.
             | 
             | There are so many things that I could probably spend
             | several hours typing them out and I don't think that is
             | really needed.
             | 
             | C++ is certainly more type safe than C, whether or not you
             | think the tradeoffs it makes are worth is something to
             | debate for sure, but it gives you tools to write type safe
             | code that simply don't exist in C.
             | 
             | https://wiki.gentoo.org/wiki/Modern_C_porting#What_changed.
             | 3...
        
         | vbtemp wrote:
         | It's not just you.
         | 
         | The only thing I'm confused about is why more C standards keep
         | coming out. C is what it is. Work with the archaic parts of it
         | as need be. You use C for ultimate cross-platform compatibility
         | (every exotic platform and its mother has an ANSI-C/C99
         | compiler). If you're able to run on the most bleeding-edge C
         | compiler supporting the most recent WG version of C... then why
         | not just use another language? I say this as someone who loves
         | C. If there are bits that feel old, you just create a DSL to
         | get around these problems that compiles down to C... but you
         | don't change C itself.. Just my perception working with all
         | this for many years now.
        
           | hgs3 wrote:
           | For me the big problem with most C competitors is they go
           | overboard. The only alternative I've tried that sparked my
           | fancy was D with -betterC flag. It's unfortunate that it's
           | not its own language, but rather a "profile" of a much much
           | larger language.
        
         | rwbt wrote:
         | There's a lot of feature gap between C and C++. Many including
         | me like to program in C but want just a _little_ more
         | safeguards, syntax sugar and some established ideas (like
         | defer) that improve the programming experience.
         | 
         | Now there are languages like Odin, Zig and C3 that are trying
         | to fill that niche but having C evolve slowly to accommodate
         | such users is also a great idea.
         | 
         | C99 added Designated Initializers which IMHO is probably the
         | most innovative declarative syntax to initialize anything and
         | it took C++ roughly 20 years to adopt such a thing (and then
         | they had to nerf it).
        
       | sfpotter wrote:
       | What problem does this solve that isn't superficial? I don't see
       | why it's important to include.
        
         | sigsev_251 wrote:
         | Generic libraries. There are programming domains in the
         | embedded world where code reuse can shorten the development
         | timeline in a significant way, which gives engineers more time
         | to test and verify.
        
           | sfpotter wrote:
           | Example? Why not just use C++?
        
             | sigsev_251 wrote:
             | Because there are platforms with no, or really buggy C++
             | support.
        
               | sfpotter wrote:
               | What is an example of an embedded systems project which
               | truly benefits from a generic library in the way that you
               | described?
        
               | sigsev_251 wrote:
               | Aviation would be my personal experience. We have to
               | implement services on the aircraft for structured
               | communication support with the ground tower. Those would
               | really benefit from something like that, since we
               | wouldn't have to implement a backend for every project
               | and we could simply reuse the whole library everywhere.
        
               | sfpotter wrote:
               | I don't see how generic programming (a la polymorphic
               | types as presented) is the only or even the best solution
               | to this problem.
        
               | phkahler wrote:
               | That sounds like a someone else's problem. Find a
               | platform that supports the language you need rather than
               | try to make C into that language.
               | 
               | It is not C's job to be everything to everyone.
        
         | uecker wrote:
         | 1. Type safety for generic interfaces such as qsort. 2.
         | Language interoperability. Then you need to have a dynamic
         | framework for constructing types and function calls.
        
           | sfpotter wrote:
           | If you're in a situation where you "truly need" type safe
           | generic interfaces, why wouldn't you just use a different
           | language?
           | 
           | I don't understand your second point.
        
             | uecker wrote:
             | There is no other languages with the same advantages as C
             | and a good type system.
        
             | uecker wrote:
             | The other point: For interoperability with other languages
             | you often need to construct function calls at run-time. For
             | this one needs to be able to describe types. Adding this by
             | external libraries is always a pain because one has to
             | carefully support the ABI of all supported architectures. A
             | compiler can support this seamlessly. A _Typeof operator
             | that returns a type that can be passed around and
             | interrogated at run-time solves this in a very elegant and
             | simple way.
        
           | hgs3 wrote:
           | Hi Martin, thank you for writing this proposal. This is just
           | my two cents, but one-off void* functions, like qsort, are
           | less of a pain point relative to generic containers. With
           | generic containers it's common to have a collection of void*
           | functions that must be consistently invoked with identical
           | type T. Correct me if I'm wrong, but this proposal cannot
           | genericize a struct field, i.e. it can genericize type 'T'
           | but not 'T->someField'. The latter would be useful for
           | something like 'vec_push(v,p)' where 'v->data[]' is the type
           | T needed to determine if 'p' is a compatible type.
           | 
           | Tangentially related, the macro-based containers you've
           | written here [1] are the best answer for type-generic
           | containers I've come across. One "gotcha" is the container
           | name must be a valid C identifier otherwise it doesn't token
           | paste correctly (see Example #2 of your REAMDE where you
           | typedef'd string* as string_ptr to workaround this). Would
           | you give consideration to a new preprocessor mechanism for
           | concatenating a list of tokens into a single valid C
           | identifier? i.e. Something like CONCAT(struct Foo *) would
           | produce struct_Foo_Ptr? The result is guaranteed token paste-
           | able.
           | 
           | [1] https://github.com/uecker/noplate
        
       | synergy20 wrote:
       | IMHO, the C committee should just copy a subset from C++, in
       | addition to having new features for free, you also make sure c
       | and c++ are 100% compatible.
        
         | up2isomorphism wrote:
         | There is no point to make sure C/C++ 100% compatible and also
         | you can not as of now.
        
       | muragekibicho wrote:
       | I use C at my day job and our company works with ANSI C. I
       | believe it's C89. I was curious to find out - who's using C23 in
       | prod? Please let me know in the comments. I'm super curious!
        
         | ptek wrote:
         | Embedded developer or are you porting software?
         | 
         | Is it C89 or gnuc89? gnuc89 is the one that allows // for
         | single line comments, I don't know what other features gnuc89
         | adds over c89.
         | 
         | I also call C89 ANSI C :)
         | 
         | Are you guys using gcc or clang?
        
       ___________________________________________________________________
       (page generated 2024-01-18 23:02 UTC)