• What is wrong with C? (and fond memories of VAX)

    From Lars Poulsen@3:633/10 to All on Tue Jan 6 15:15:44 2026
    [Note Followup-To]

    On 2026-01-06, Carlos E.R. <robin_listas@es.invalid> wrote:
    My C teacher said it was a mistake to use C as an all purpose language,
    like for userland applications. Using C is the cause of many bugs that a proper language would catch.

    That was around 1991.

    He knew. He participated in some study tasked by the Canadian government
    to study C compilers, but he could not talk about what they wrote.

    I agree that C does the job reasonably well, and it is simple.
    And so, like most other geeks my age, I write with the tools I
    have used in forever, rather than spending my time learning new
    tools. For me, those tools are:
    - C
    - vim
    - perl
    - HTML (1.0)
    And yes, it is like using a vintage Jeep for a daily driver.

    The most egregious problem with old C is string handling.
    A useful "string" type would have
    - a maximum length, using hardware (exception) bounds checking.
    to be useful, this would mean a length field in front of
    the char[]
    - ideally, an option for the length to be dynamic, reallocating
    the memory as needed. Would require the base representation
    to be a pointer to the struct. Would be a lot of "under the
    hood" stuff, and probably inefficient.

    ** and now a digression **

    The VAX architecture with its descriptors and universal calling
    sequences was a great foundation, but K&R C did not fit, because
    a byte-addressed memory was assumed, and you could not put the
    descriptors in the middle of a struct and still have the code be
    portable. So for anything with networking, which relied on being
    able to import the Berkeley networking code, all the descriptor
    stuff was of no use. For a lot of other code, it was amazingly
    good. The unified calling structure and the way an exception
    could be unwound up multiple levels of stack and simply be
    converted to an error return code at the top level of a layered
    library was pretty miraculous. And the instruction set was
    very intuitive. I wrote a lot of kernel code in Macro-32,
    and it was almost as fast as writing C.

    The people in comp.arch look down of how inefficient the VAX
    was, and how the microcode tricks used to make fast CPUs with
    pipelining and out-of-order execution would not work for a VAX.
    I think that is just an example of how the arch of history often
    looks inevitable in hindsight.
    --
    Lars Poulsen - an old geek in Santa Barbara, California

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Charlie Gibbs@3:633/10 to All on Tue Jan 6 18:57:04 2026
    On 2026-01-06, Lars Poulsen <lars@beagle-ears.com> wrote:

    On 2026-01-06, Carlos E.R. <robin_listas@es.invalid> wrote:

    My C teacher said it was a mistake to use C as an all purpose language,
    like for userland applications. Using C is the cause of many bugs that a
    proper language would catch.

    That was around 1991.

    He knew. He participated in some study tasked by the Canadian government
    to study C compilers, but he could not talk about what they wrote.

    What language(s) did he suggest instead?

    I agree that C does the job reasonably well, and it is simple.
    And so, like most other geeks my age, I write with the tools I
    have used in forever, rather than spending my time learning new
    tools. For me, those tools are:
    - C
    - vim
    - perl
    - HTML (1.0)
    And yes, it is like using a vintage Jeep for a daily driver.

    You mean pulling those fancy cars out of a ditch? It's fun...

    The most egregious problem with old C is string handling.
    A useful "string" type would have
    - a maximum length, using hardware (exception) bounds checking.
    to be useful, this would mean a length field in front of
    the char[]
    - ideally, an option for the length to be dynamic, reallocating
    the memory as needed. Would require the base representation
    to be a pointer to the struct. Would be a lot of "under the
    hood" stuff, and probably inefficient.

    Inspired by readline(), I've written my own replacements for
    strcpy() and strcat() that do much the same thing.

    --
    /~\ Charlie Gibbs | Growth for the sake of
    \ / <cgibbs@kltpzyxm.invalid> | growth is the ideology
    X I'm really at ac.dekanfrus | of the cancer cell.
    / \ if you read it the right way. | -- Edward Abbey

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Lawrence D?Oliveiro@3:633/10 to All on Tue Jan 6 20:04:58 2026
    On Tue, 6 Jan 2026 07:55:03 -0700, Peter Flass wrote:

    PL/I was designed with all the features that were later added to C,
    so the end result is cleaner.

    PL/I had its own surprises, possibly like C++, maybe even worse.
    Like automatic type conversions that produce entirely unexpected
    results.

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Scott Lurndal@3:633/10 to All on Tue Jan 6 21:59:54 2026
    rbowman <bowman@montana.com> writes:
    On Tue, 06 Jan 2026 18:57:04 GMT, Charlie Gibbs wrote:

    Inspired by readline(), I've written my own replacements for strcpy()
    and strcat() that do much the same thing.

    To quote from the strcat man page "Read about Shlemiel the painter.". >stpcpy() was a late arrival and I never used it. I do use a similar >construct

    char buf[1024];
    char* ptr = buf;

    ptr += sprintf(ptr, "%s", "some stuff");
    ptr += sprintf(ptr, "%s", " some more stuff");

    I would suggest using snprintf instead of sprintf
    to prevent accesses beyond (buf + 1024). A bit
    more complicated if you want to know that the
    result was truncated, since you need to adjust the
    remaining length based on the return value from
    the prior snprintf, as well as checking for
    overflow.


    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Richard Kettlewell@3:633/10 to All on Tue Jan 6 22:54:26 2026
    scott@slp53.sl.home (Scott Lurndal) writes:
    rbowman <bowman@montana.com> writes:
    On Tue, 06 Jan 2026 18:57:04 GMT, Charlie Gibbs wrote:
    Inspired by readline(), I've written my own replacements for strcpy()
    and strcat() that do much the same thing.

    To quote from the strcat man page "Read about Shlemiel the painter.". >>stpcpy() was a late arrival and I never used it. I do use a similar >>construct

    char buf[1024];
    char* ptr = buf;

    ptr += sprintf(ptr, "%s", "some stuff");
    ptr += sprintf(ptr, "%s", " some more stuff");

    I would suggest using snprintf instead of sprintf
    to prevent accesses beyond (buf + 1024). A bit
    more complicated if you want to know that the
    result was truncated, since you need to adjust the
    remaining length based on the return value from
    the prior snprintf, as well as checking for
    overflow.

    This is calling out for a wrapping up in a function or two that can do
    the book-keeping automatically (and use an expandable buffer, if the use
    case demands).

    --
    https://www.greenend.org.uk/rjk/

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Charlie Gibbs@3:633/10 to All on Wed Jan 7 06:33:50 2026
    On 2026-01-07, rbowman <bowman@montana.com> wrote:

    On Tue, 06 Jan 2026 22:54:26 +0000, Richard Kettlewell wrote:

    scott@slp53.sl.home (Scott Lurndal) writes:

    rbowman <bowman@montana.com> writes:

    On Tue, 06 Jan 2026 18:57:04 GMT, Charlie Gibbs wrote:

    Inspired by readline(), I've written my own replacements for strcpy() >>>>> and strcat() that do much the same thing.

    To quote from the strcat man page "Read about Shlemiel the painter.".
    stpcpy() was a late arrival and I never used it. I do use a similar
    construct

    char buf[1024];
    char* ptr = buf;

    ptr += sprintf(ptr, "%s", "some stuff");
    ptr += sprintf(ptr, "%s", " some more stuff");

    I would suggest using snprintf instead of sprintf to prevent accesses
    beyond (buf + 1024). A bit more complicated if you want to know that
    the result was truncated, since you need to adjust the remaining length
    based on the return value from the prior snprintf, as well as checking
    for overflow.

    This is calling out for a wrapping up in a function or two that can do
    the book-keeping automatically (and use an expandable buffer, if the use
    case demands).

    Ah, mission creep...

    Yes, I haven't been able to justify doing an equivalent for sprintf() yet.

    --
    /~\ Charlie Gibbs | Growth for the sake of
    \ / <cgibbs@kltpzyxm.invalid> | growth is the ideology
    X I'm really at ac.dekanfrus | of the cancer cell.
    / \ if you read it the right way. | -- Edward Abbey

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Carlos E.R.@3:633/10 to All on Wed Jan 7 13:30:14 2026
    On 2026-01-06 19:57, Charlie Gibbs wrote:
    On 2026-01-06, Lars Poulsen <lars@beagle-ears.com> wrote:

    On 2026-01-06, Carlos E.R. <robin_listas@es.invalid> wrote:

    My C teacher said it was a mistake to use C as an all purpose language,
    like for userland applications. Using C is the cause of many bugs that a >>> proper language would catch.

    That was around 1991.

    He knew. He participated in some study tasked by the Canadian government >>> to study C compilers, but he could not talk about what they wrote.

    What language(s) did he suggest instead?

    I don't remember if he did. Maybe he told samples, but I think he mostly
    told us of quirks of the language, things that were errors, but that the compiler did not signal, so that we being aware we would write correct C
    code.

    It is possible that current C compilers signal many more problems that
    back then, but not runtime errors.

    I would have to seek my hand notes.

    Mostly accessing variables beyond the end of it. Arrays or strings were
    the most blatant example.

    ...
    --
    Cheers, Carlos.
    ES??, EU??;

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From c186282@3:633/10 to All on Thu Jan 8 00:47:23 2026
    On 1/7/26 17:49, rbowman wrote:
    On Wed, 7 Jan 2026 13:30:14 +0100, Carlos E.R. wrote:

    On 2026-01-06 19:57, Charlie Gibbs wrote:
    On 2026-01-06, Lars Poulsen <lars@beagle-ears.com> wrote:

    On 2026-01-06, Carlos E.R. <robin_listas@es.invalid> wrote:

    My C teacher said it was a mistake to use C as an all purpose
    language, like for userland applications. Using C is the cause of
    many bugs that a proper language would catch.

    That was around 1991.

    He knew. He participated in some study tasked by the Canadian
    government to study C compilers, but he could not talk about what
    they wrote.

    What language(s) did he suggest instead?

    I don't remember if he did. Maybe he told samples, but I think he mostly
    told us of quirks of the language, things that were errors, but that the
    compiler did not signal, so that we being aware we would write correct C
    code.

    It is possible that current C compilers signal many more problems that
    back then, but not runtime errors.

    gcc has become pickier. That isn't always a welcome thing when working
    with legacy code and requires a search of the compiler options to get it
    to shut up about such horrible heresies as assuming a function returns an int.

    Yea ... noticed this trend.

    I *suppose* it's "for the best" ... however .....

    Admit it ... people OFTEN write HORRIBLE code with
    all sorts of 'assumptions' and security-vulnerable
    stuff in there. It's probably why M$ has some major
    security prob listed every week .....


    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From The Natural Philosopher@3:633/10 to All on Thu Jan 8 11:23:36 2026
    On 07/01/2026 22:49, rbowman wrote:
    On Wed, 7 Jan 2026 13:30:14 +0100, Carlos E.R. wrote:

    On 2026-01-06 19:57, Charlie Gibbs wrote:
    On 2026-01-06, Lars Poulsen <lars@beagle-ears.com> wrote:

    On 2026-01-06, Carlos E.R. <robin_listas@es.invalid> wrote:

    My C teacher said it was a mistake to use C as an all purpose
    language, like for userland applications. Using C is the cause of
    many bugs that a proper language would catch.

    That was around 1991.

    He knew. He participated in some study tasked by the Canadian
    government to study C compilers, but he could not talk about what
    they wrote.

    What language(s) did he suggest instead?

    I don't remember if he did. Maybe he told samples, but I think he mostly
    told us of quirks of the language, things that were errors, but that the
    compiler did not signal, so that we being aware we would write correct C
    code.

    It is possible that current C compilers signal many more problems that
    back then, but not runtime errors.

    gcc has become pickier. That isn't always a welcome thing when working
    with legacy code and requires a search of the compiler options to get it
    to shut up about such horrible heresies as assuming a function returns an int.


    Actually I welcome that. at leats 10% of the time the compiler finds a
    bug that way, and the other 90% i upgrade the source to be more explicit...





    --
    The theory of Communism may be summed up in one sentence: Abolish all
    private property.

    Karl Marx



    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Charlie Gibbs@3:633/10 to All on Thu Jan 8 19:16:38 2026
    On 2026-01-08, The Natural Philosopher <tnp@invalid.invalid> wrote:

    On 07/01/2026 22:49, rbowman wrote:

    On Wed, 7 Jan 2026 13:30:14 +0100, Carlos E.R. wrote:

    It is possible that current C compilers signal many more problems that
    back then, but not runtime errors.

    gcc has become pickier. That isn't always a welcome thing when working
    with legacy code and requires a search of the compiler options to get it
    to shut up about such horrible heresies as assuming a function returns an
    int.

    Actually I welcome that. at leats 10% of the time the compiler finds a
    bug that way, and the other 90% i upgrade the source to be more explicit...

    +1

    I re-worked my code over time so that -Wall yields no errors.
    And then a new version of gcc comes out which picks even more
    nits, and the process repeats. Not being a quick-and-dirty
    type, I consider it a win overall.

    The one exception is its scrutiny of printf() calls.
    That was a step too far, so I added -Wno-format-overflow.

    --
    /~\ Charlie Gibbs | Growth for the sake of
    \ / <cgibbs@kltpzyxm.invalid> | growth is the ideology
    X I'm really at ac.dekanfrus | of the cancer cell.
    / \ if you read it the right way. | -- Edward Abbey

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Charlie Gibbs@3:633/10 to All on Thu Jan 8 22:45:45 2026
    On 2026-01-08, rbowman <bowman@montana.com> wrote:

    It was never a good idea but the legacy code often defined a variable in
    a .h file. The newer gcc implementations would throw multiple definition errors. Fixing it would have been painful. foo.h that defined int bar;
    might be included in several different programs so you would have to hunt down all the uses and then define bar someplace in a .c file.

    Great project for the new guy but at the time the newest guy had been
    there for 20 years. Adding the compiler flag to the relevant makefiles was easier.

    In multi-module programs I define my globals in a .h file as follows:

    common.h
    --------
    #ifdef PRIMARY
    #define GLOBAL
    #else
    #define GLOBAL extern
    #endif

    foo.h
    -----
    #include "common.h"
    GLOBAL int foo;

    foo1.c
    ------
    #define PRIMARY
    #include "foo.h"
    int main(int argc, char **argv)
    {
    setfoo();
    printf("foo is %d\n", foo);
    exit(0);
    }

    foo2.c
    ------
    #include "foo.h"
    void setfoo()
    {
    foo = 5;
    }

    It works for me; I like having only one declaration of "foo"
    in my source modules.

    --
    /~\ Charlie Gibbs | Growth for the sake of
    \ / <cgibbs@kltpzyxm.invalid> | growth is the ideology
    X I'm really at ac.dekanfrus | of the cancer cell.
    / \ if you read it the right way. | -- Edward Abbey

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From sean@3:633/10 to All on Fri Jan 9 00:23:45 2026
    In alt.folklore.computers Charlie Gibbs <cgibbs@kltpzyxm.invalid> wrote:
    In multi-module programs I define my globals in a .h file as follows:

    common.h
    --------
    #ifdef PRIMARY
    #define GLOBAL
    #else
    #define GLOBAL extern
    #endif

    foo.h
    -----
    #include "common.h"
    GLOBAL int foo;

    foo1.c
    ------
    #define PRIMARY
    #include "foo.h"
    int main(int argc, char **argv)
    {
    setfoo();
    printf("foo is %d\n", foo);
    exit(0);
    }

    foo2.c
    ------
    #include "foo.h"
    void setfoo()
    {
    foo = 5;
    }

    It works for me; I like having only one declaration of "foo"
    in my source modules.

    I used to do that, and I eventually didn't like it. I then switched to declaring all my global variables in one file:

    globals.c
    --------

    int c_maxitems;
    char const *c_name = "Blah de blah blah";
    int g_foo;

    This file will also contain the code to set global variables that I
    consider "constant" (the variables that start with "c_"). This allows them
    to be set at program start up. Then the include file:

    globals.h
    ---------

    extern int const c_maxitems;
    extern char const *const c_name;
    extern int g_foo;

    extern int global_init(int,char *[]);

    Note: "globals.c" will never include "gloabls.h". Oh, and the weird const placement? That avoid the that weird C-spiral rule. The way I use "const" these days means it applies to the thing on the right:

    char * p; // mutable pointer to mutable char
    char const * q; // mutable pointer to constant char
    char *const r; // constant pointer to mutable char
    char const *const s; // constant pointer to constant char

    Recently, I've been writing code with no global variables. It's been a
    fun experiment.

    -spc (Why yes, I do have a structure that gets passed to every function,
    why do you ask?)

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Lawrence D?Oliveiro@3:633/10 to All on Fri Jan 9 04:54:56 2026
    On Fri, 9 Jan 2026 00:23:45 -0000 (UTC), sean wrote:

    Recently, I've been writing code with no global variables. It's been
    a fun experiment.

    When I started looking at the Blender source code, I came across these
    global variables called ?G? and ?C?. They contained context relating
    to the currently-open document.

    Finding out where they were defined, across over a million lines of
    source code, was a fun exercise. I learned somethings about ctags
    along the way ...

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Scott Lurndal@3:633/10 to All on Fri Jan 9 16:18:59 2026
    Charlie Gibbs <cgibbs@kltpzyxm.invalid> writes:
    On 2026-01-08, rbowman <bowman@montana.com> wrote:

    It was never a good idea but the legacy code often defined a variable in
    a .h file. The newer gcc implementations would throw multiple definition
    errors. Fixing it would have been painful. foo.h that defined int bar;
    might be included in several different programs so you would have to hunt >> down all the uses and then define bar someplace in a .c file.

    Great project for the new guy but at the time the newest guy had been
    there for 20 years. Adding the compiler flag to the relevant makefiles was >> easier.

    In multi-module programs I define my globals in a .h file as follows:

    common.h
    --------
    #ifdef PRIMARY
    #define GLOBAL
    #else
    #define GLOBAL extern
    #endif

    Canonically speaking, one uses an 'include guard' to ensure that
    a header file is only included once.

    Typically

    common.h
    -------
    #if !defined(__common_h__)
    #define __common_h__

    <header file content>

    #endif

    In modern C/C++ you can also do this with a single line in the header file

    #pragma once



    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Carlos E.R.@3:633/10 to All on Mon Jan 12 15:44:56 2026
    On 2026-01-07 23:49, rbowman wrote:
    On Wed, 7 Jan 2026 13:30:14 +0100, Carlos E.R. wrote:

    On 2026-01-06 19:57, Charlie Gibbs wrote:
    On 2026-01-06, Lars Poulsen <lars@beagle-ears.com> wrote:

    On 2026-01-06, Carlos E.R. <robin_listas@es.invalid> wrote:

    My C teacher said it was a mistake to use C as an all purpose
    language, like for userland applications. Using C is the cause of
    many bugs that a proper language would catch.

    That was around 1991.

    He knew. He participated in some study tasked by the Canadian
    government to study C compilers, but he could not talk about what
    they wrote.

    What language(s) did he suggest instead?

    I don't remember if he did. Maybe he told samples, but I think he mostly
    told us of quirks of the language, things that were errors, but that the
    compiler did not signal, so that we being aware we would write correct C
    code.

    It is possible that current C compilers signal many more problems that
    back then, but not runtime errors.

    gcc has become pickier. That isn't always a welcome thing when working
    with legacy code and requires a search of the compiler options to get it
    to shut up about such horrible heresies as assuming a function returns an int.

    If the code were mine, I would correct the code. Even back then, I did
    not take the assumption that a function would return an integer :-D

    I wrote explicit prototypes in the header file. :-)


    If the code is not mine, I would use the compiler options instead.
    Unless I got paid to maintain that code, then I would correct the code.

    --
    Cheers, Carlos.
    ES??, EU??;

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Lawrence D?Oliveiro@3:633/10 to All on Mon Jan 12 19:59:30 2026
    On Mon, 12 Jan 2026 15:44:56 +0100, Carlos E.R. wrote:

    If the code were mine, I would correct the code. Even back then, I
    did not take the assumption that a function would return an integer
    :-D

    That?s why they call it ?technical debt?. And yes, like any debt, it
    incurs interest -- compound interest, even ...

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Chris Ahlstrom@3:633/10 to All on Tue Jan 13 06:13:51 2026
    Carlos E.R. wrote this post by blinking in Morse code:

    On 2026-01-07 23:49, rbowman wrote:

    On 2026-01-06 19:57, Charlie Gibbs wrote:

    <snip>

    It is possible that current C compilers signal many more problems that
    back then, but not runtime errors.

    Gcc will tag things that could cause a run-time error, such as
    parameters that don't match the specifiers in a printf() call.

    gcc has become pickier. That isn't always a welcome thing when working
    with legacy code and requires a search of the compiler options to get it
    to shut up about such horrible heresies as assuming a function returns an
    int.

    I periodically also build projects using clang. Clang and gcc each
    catch some problems that the other does not catch.

    If the code were mine, I would correct the code. Even back then, I did
    not take the assumption that a function would return an integer :-D

    I wrote explicit prototypes in the header file. :-)

    If the code is not mine, I would use the compiler options instead.
    Unless I got paid to maintain that code, then I would correct the code.

    Don't fix what ain't broke, you might break it [1] :-D

    [1] I'm speaking from experience.

    --
    You can observe a lot just by watching. -- Yogi Berra

    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)