• Making more of the C standard library mandatory for freestanding im

    From upsidedown@downunder.com@21:1/5 to All on Thu May 7 08:59:59 2020
    On Wed, 6 May 2020 18:19:31 +0200, Philipp Klaus Krause <pkk@spth.de>
    wrote:

    In C, most of the standard library is mandatory for hosted
    implementations only, not for freestadning implementations.
    Still, I see many functions, such as memcpy() and abs() often used in >programs for embedded systems, and see no obstacles to implementing them
    even on small systems.

    The question is, are primitive functions like memcpy(), strcpy() or
    abs() truly "library functions" or just syntactic sugar for missing
    C-language constructs. In practice, any good compiler will implement
    these just as in-line code instead of calling a library function with
    all the parameter passing mess.

    On a processor without a multiplication instruction might require a
    library function to implement eg. a 16x16 bit multiply. However, if
    the application only requires multiply by small constant (e.g. in
    array index references), the compiler could do inline shifts and adds
    instead.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Keith Thompson on Thu May 7 06:08:18 2020
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    [...] there's nothing in the Standard to say that a freestanding implementation that implements part of the hosted standard library
    has to do it correctly.

    I'm not sure that's right. A freestanding implementation isn't
    required to accept programs that use those headers, but I don't
    see anything that would allow the implementation to violate their specifications either. Also, the Standard says implementations
    may have extensions provided they do not alter the behavior of
    /any/ strictly conforming program. The definition of strictly
    conforming program includes all library facilities, not just
    those required of freestanding implementations. Certainly a
    freestanding implemention is free not to provide any library
    facilities beyond its minimal required set, but AFAIK there isn't
    any provision that would allow it to change the behavior of any
    it does provide.

    Please note, I'm not making an argument that the statement is
    wrong. But I do think the answer is not completely clearcut, and
    the question is open to debate.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Philipp Klaus Krause on Thu May 7 06:14:48 2020
    Philipp Klaus Krause <pkk@spth.de> writes:

    In C, most of the standard library is mandatory for hosted
    implementations only, not for freestadning implementations.
    Still, I see many functions, such as memcpy() and abs() often used in programs for embedded systems, and see no obstacles to implementing them
    even on small systems.

    Should more of the standard library become mandatory for freestanding implementations?

    For string.h, I have written a first draft of a proposal:

    http://www.colecovision.eu/stuff/proposal-freestanding-string.html

    What do you think of it?

    Do you see any reason those could not be provided on some C implementation?

    Which further functions would you like to become mandatory for
    freestanding C implementations?

    I second the comments of Grant Edwards and Hans-Bernhard Broeker.

    Freestanding implementations may provide whatever additional
    library facilities they choose, but the required set should
    be kept where it is, at an absolute minimum.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Philipp Klaus Krause@21:1/5 to All on Thu May 7 21:38:02 2020
    Am 07.05.20 um 15:14 schrieb Tim Rentsch:
    Freestanding implementations may provide whatever additional
    library facilities they choose, but the required set should
    be kept where it is, at an absolute minimum.

    Why?

    By the same argument you could make support for int or anything else
    optional for freestanding implemnentations.
    Stuff that cannot be implemented easily on certain hardware should
    surely be optional (or even better, the standard should try to avoid introducing features in a way that make them hard or inefficient to
    implement on certain types of hardware).

    But I haven't yet seen a good reason to keep stuff like memcpy() that
    can easily be implemented on any hardware on which C can be implemented
    at all, optional.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Paul Rubin on Fri May 8 08:38:14 2020
    Paul Rubin <no.email@nospam.invalid> writes:

    Philipp Klaus Krause <pkk@spth.de> writes:

    For many embedded users, memcpy() might be more useful and necessary
    than long long or float. Also, memcpy() is easier to implement than
    support for long long or float. Still the latter are currently mandatory
    for freestanding implementations, while the former is not.

    Forth has a core wordset (basically a library) and a bunch of separate optional wordsets, each of which is standardized. Floating point
    arithmetic is an optional wordset so it's fine if your implementation
    doesn't have it. But if you do choose to supply floating point
    features, the standard says what those features should do, so you don't
    have to make it up as you go along.

    Maybe C could use a similar approach.

    What I like about your idea is the notion that an interface is
    standardized, and an implementation gets a binary choice,
    either to provide it as specified, or just not to provide it.

    To make that idea work for case under discussion here (ie, for
    string functions), I think that needs to be augmented in two
    ways. One, it needs to be more fine grained than just all of
    <string.h>. Two, it needs to include a way for a program source
    to inquire about whether any particular function has been
    provided -- probably done using preprocessor symbols -- so that
    the program can adapt to different environments, and do that
    automatically, without needing to have a separate configuration
    step.

    For example, under this scheme, we might do this:

    // File "fs_string.h"

    #include <string-optional.h> // string.h optional subset

    #if ! _Provides_strlen
    extern size_t strlen( const char * );
    #endif

    ...

    // File "fs_string.c"

    #include "fs_string.h"

    #if ! _Provides_strlen
    size_t
    strlen( const char *s ){
    size_t r = 0;
    while( *s++ ) r++;
    return r;
    }

    #endif

    Now the rest of the program can simply #include "fs_string.h",
    and use strlen() just as it would if strlen() was supplied
    by the implementation.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Philipp Klaus Krause on Fri May 8 12:03:26 2020
    Philipp Klaus Krause <pkk@spth.de> writes:

    Am 07.05.20 um 15:14 schrieb Tim Rentsch:

    Freestanding implementations may provide whatever additional
    library facilities they choose, but the required set should
    be kept where it is, at an absolute minimum.

    Why?

    I would turn that question around and ask why should the minimum
    be raised? Your written proposal doesn't offer even any good
    arguments, let alone any compelling or convincing ones.

    By the same argument you could make support for int or anything else
    optional for freestanding implemnentations.

    That's wrong. The case for int is not at all the same argument.

    * Every program uses int. Not every program uses any
    <string.h> functions.

    * Supporting int has no runtime footprint costs even on
    pretty tiny processors. Functions in <string.h> often do.

    * Support for int on freestanding implementations is already
    in the Standard. The default position is always in favor
    of the status quo. Removing support for int would need at
    the very least a compelling argument to do so; leaving it
    in needs no argument at all. This situation is exactly
    reversed for the <string.h> proposal.

    Stuff that cannot be implemented easily on certain hardware should
    surely be optional (or even better, the standard should try to avoid introducing features in a way that make them hard or inefficient to
    implement on certain types of hardware).

    Personally I think there are reasons to consider lowering the
    requirements on freestanding implementations for integer types
    wider than int, and perhaps make floating point optional entirely.
    But that is another conversation. Your argument is basically "if
    it can be done then it should be done." First off the "can be
    done" part has not been established. Second, even if it were,
    it's a bogus argument. A lot of programs (that would run on very
    small processors and thus on freestanding implementations) don't
    need any functions from <string.h>. A minimal standard should be
    exactly that: minimal.

    The idea that <string.h> should be mandatory everywhere is part of
    a broader trend that C should be made more uniform by insisting
    that implementations be more homogenous. A justification sometimes
    offered for this is so programs will be "more portable" (and indeed
    this aspect is mentioned in your proposal). That reasoning is
    fundamentally misguided. C isn't like Ada, where its use can be
    mandated, and certification is necessary. If the bar is raised,
    the "offending implementations" won't change, they will just be
    left as non-conforming. That effect will /reduce/ the incentive to
    comply with the rest of the Standard, not raise it. Fundamental
    truth: programs are not made "more portable" by limiting the set
    of platforms (HW+SW) that have conforming implementations.
    Applications don't have to support every possible conforming
    implementation; they are perfectly free to rule out any that don't
    give them what they need (ideally with preprocessor conditionals or
    static assertions, but that is a separate topic). But thinking a
    program is "more portable" by virtue of having ruled out all
    implementations where it wouldn't work is like an ostrich sticking
    its head in the sand.

    But I haven't yet seen a good reason to keep stuff like memcpy()
    that can easily be implemented on any hardware on which C can be
    implemented at all, optional.

    First, that isn't what you're proposing. The proposal says
    <string.h>, not memcpy().

    Second, the use of "easily" is too glib. You haven't made any
    effort, at least not that I can see, to quantify the cost on
    implementations to comply with the suggested additions. (Also,
    the proposal is a bit vague about exactly what /is/ being
    suggested, and this deficiency needs to be corrected before
    the proposal should receive any further serious attention.)

    Third, there is no mention of any possible alternatives that
    might satisfy the needs. Come to think of it, there wasn't
    any statement of what the needs are - the proposal looks like
    a solution in search of a problem.

    Fourth, and perhaps most important, you don't seem to grasp that
    since you are the one proposing a change, it's up to you to find
    reasoning that convinces others that it _should_ be done, not up
    to others to find reasons that convince you that it _shouldn't_
    be done. Your proposal, your burden of proof.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Philipp Klaus Krause@21:1/5 to All on Fri May 8 21:27:50 2020
    Am 08.05.20 um 21:03 schrieb Tim Rentsch:
    Philipp Klaus Krause <pkk@spth.de> writes:

    Am 07.05.20 um 15:14 schrieb Tim Rentsch:

    Freestanding implementations may provide whatever additional
    library facilities they choose, but the required set should
    be kept where it is, at an absolute minimum.

    Why?

    I would turn that question around and ask why should the minimum
    be raised? Your written proposal doesn't offer even any good
    arguments, let alone any compelling or convincing ones.

    […]

    The idea that <string.h> should be mandatory everywhere is part of
    a broader trend that C should be made more uniform by insisting
    that implementations be more homogenous. A justification sometimes
    offered for this is so programs will be "more portable" (and indeed
    this aspect is mentioned in your proposal). That reasoning is
    fundamentally misguided. C isn't like Ada, where its use can be
    mandated, and certification is necessary. If the bar is raised,
    the "offending implementations" won't change, they will just be
    left as non-conforming. That effect will /reduce/ the incentive to
    comply with the rest of the Standard, not raise it. Fundamental
    truth: programs are not made "more portable" by limiting the set
    of platforms (HW+SW) that have conforming implementations.
    Applications don't have to support every possible conforming
    implementation; they are perfectly free to rule out any that don't
    give them what they need (ideally with preprocessor conditionals or
    static assertions, but that is a separate topic). But thinking a
    program is "more portable" by virtue of having ruled out all
    implementations where it wouldn't work is like an ostrich sticking
    its head in the sand.

    Functionality in the C standard is there, since it was found useful to
    many C programmers - otherwise it wouldn't have made it into the standard.
    I propose making some functionality that is already in the C standard
    mandatory for freestanding implementations.
    And indeed, I see uses of string.h functions in many programs for tiny
    devices.
    Sometimes, to be portable cross freestanding implementations, users roll
    their own versions.

    I do not see adding functionality, that can be easily added to any C implementation as reducing the incentive to comply with the standard. On
    the other hand, that would surely be true for features that are complex
    to implement or hard to implement efficiently on some hardware (SDCC
    does not support VLAs, and thus is more complete in C17 support than in
    C99 support).

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Philipp Klaus Krause@21:1/5 to All on Fri May 8 21:15:38 2020
    Am 08.05.20 um 21:03 schrieb Tim Rentsch:

    * Supporting int has no runtime footprint costs even on
    pretty tiny processors. Functions in <string.h> often do.

    […]

    Second, the use of "easily" is too glib. You haven't made any
    effort, at least not that I can see, to quantify the cost on
    implementations to comply with the suggested additions. (Also,
    the proposal is a bit vague about exactly what /is/ being
    suggested, and this deficiency needs to be corrected before
    the proposal should receive any further serious attention.)


    SDCC is a pretty simple C implementation in most aspects (there is some
    fancy stuff in register allocation, but that is irrelevant to what we
    are discussing here), that targets various small devices, down to microcontrollers like the Padauk PMS15A (priced at about 0.01€ when
    bought in quantities of 10, has 64 B of RAM, 0.5 KW of 13-bit wide
    program memory). The linker is very simple and can't do anything fancy.

    The standard library that comes with SDCC provides the full set of
    string.h functions from the latest standard draft.
    As long as none of these functions is used, none of it gets linked into
    the final binary.

    Thus, clearly the functions in string.h can be easily implemented in a
    way that there is no runtime footprint for unused functions. And for
    used functions, I don't see any reason why requiring the user to roll
    their own implementation should result in any resource savings.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Philipp Klaus Krause@21:1/5 to All on Fri May 8 21:30:11 2020
    Am 08.05.20 um 17:38 schrieb Tim Rentsch:

    For example, under this scheme, we might do this:

    // File "fs_string.h"

    #include <string-optional.h> // string.h optional subset

    #if ! _Provides_strlen
    extern size_t strlen( const char * );
    #endif

    ...

    // File "fs_string.c"

    #include "fs_string.h"

    #if ! _Provides_strlen
    size_t
    strlen( const char *s ){
    size_t r = 0;
    while( *s++ ) r++;
    return r;
    }

    #endif

    Now the rest of the program can simply #include "fs_string.h",
    and use strlen() just as it would if strlen() was supplied
    by the implementation.


    But this example also shows that it is relatively easy to implement
    strlen(), so there is not much burden on implementations when requiring
    them to provide it. And it shows that strlen not being mandatory for freestanding implementations results in lots of duplicated code in
    software projects that target these implementations.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Tim Rentsch on Sat May 9 00:25:34 2020
    On 08/05/2020 21:03, Tim Rentsch wrote:
    Philipp Klaus Krause <pkk@spth.de> writes:

    Am 07.05.20 um 15:14 schrieb Tim Rentsch:

    Freestanding implementations may provide whatever additional
    library facilities they choose, but the required set should
    be kept where it is, at an absolute minimum.

    Why?

    I would turn that question around and ask why should the minimum
    be raised? Your written proposal doesn't offer even any good
    arguments, let alone any compelling or convincing ones.

    By the same argument you could make support for int or anything else
    optional for freestanding implemnentations.

    That's wrong. The case for int is not at all the same argument.

    * Every program uses int. Not every program uses any
    <string.h> functions.

    That is not the case for small embedded systems. On 8-bit cpus, "int"
    is invariably 16-bit, and you will want to use int8_t and uint8_t as
    much as you can. It's only going to be very small programs that don't
    use "int" (or other 16-bit types, like int16_t or uint16_t), but when
    you have a microcontroller from the bottom end of the list, all your
    programs are small. (I have used an 8-bit cpu with no ram, 32 8-bit
    registers, and 1K of program space. I programmed it in C with gcc, and
    I did not use "int". It was probably the smallest real program I have written.)


    * Supporting int has no runtime footprint costs even on
    pretty tiny processors. Functions in <string.h> often do.


    For many small processors, supporting "int" involves a fair number of
    "language support library" routines, for handling multiplication,
    division, and shifts.

    * Support for int on freestanding implementations is already
    in the Standard. The default position is always in favor
    of the status quo. Removing support for int would need at
    the very least a compelling argument to do so; leaving it
    in needs no argument at all. This situation is exactly
    reversed for the <string.h> proposal.

    Agreed.


    Stuff that cannot be implemented easily on certain hardware should
    surely be optional (or even better, the standard should try to avoid
    introducing features in a way that make them hard or inefficient to
    implement on certain types of hardware).

    Personally I think there are reasons to consider lowering the
    requirements on freestanding implementations for integer types
    wider than int, and perhaps make floating point optional entirely.
    But that is another conversation.

    There is no need. People making and using compilers for such small
    systems have no qualms about non-conforming toolchains. No one using an
    8-bit AVR is put off by a compiler having 32-bit "double", or not
    supporting "long long" (even if it supports most of the rest of C99).
    These things are already optional - because putting a "standards
    compliant" stamp on a toolchain is optional.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Jakob Bohm@21:1/5 to Philipp Klaus Krause on Fri May 15 15:13:06 2020
    On 2020-05-08 21:27, Philipp Klaus Krause wrote:
    Am 08.05.20 um 21:03 schrieb Tim Rentsch:
    Philipp Klaus Krause <pkk@spth.de> writes:

    Am 07.05.20 um 15:14 schrieb Tim Rentsch:

    Freestanding implementations may provide whatever additional
    library facilities they choose, but the required set should
    be kept where it is, at an absolute minimum.

    ...

    Functionality in the C standard is there, since it was found useful to
    many C programmers - otherwise it wouldn't have made it into the standard.
    I propose making some functionality that is already in the C standard mandatory for freestanding implementations.
    And indeed, I see uses of string.h functions in many programs for tiny devices.
    Sometimes, to be portable cross freestanding implementations, users roll their own versions.

    I do not see adding functionality, that can be easily added to any C implementation as reducing the incentive to comply with the standard. On
    the other hand, that would surely be true for features that are complex
    to implement or hard to implement efficiently on some hardware (SDCC
    does not support VLAs, and thus is more complete in C17 support than in
    C99 support).


    What has been thoroughly missing from this discussion is that the formal definition of a "freestanding implementation" serves 3 separate but
    somewhat related purposes:

    1. To be a minimum implementation for compiling bare metal software that
    already includes all needed library functions, such as the Linux, BSD
    and Windows kernels.

    2. To be a specification for the part that is delivered by a compiler
    team such as gcc or llvm/clang as mostly independent from the part
    delivered by a library team such as glibc, newlib, MS UCRT and Apple
    C library.
    For example, all 4 C library implementations above are routinely both
    used with gcc, llvm/clang and (for the MS UCRT case) the vendor C
    library.

    3. To be a specification for a compiler useful for targeting tiny
    microcontrollers with minimal memory etc.

    In practice, the division of labor described as #2 is more common than
    #3, which is in turn more common #1.

    Many big projects would be upset by changes interfering with #2 and #1,
    while many projects under #3 would have little use for additions or
    already have them in a vendor kit.



    Enjoy

    Jakob
    --
    Jakob Bohm, CIO, Partner, WiseMo A/S. https://www.wisemo.com
    Transformervej 29, 2860 Søborg, Denmark. Direct +45 31 13 16 10
    This public discussion message is non-binding and may contain errors.
    WiseMo - Remote Service Management for PCs, Phones and Embedded

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Philipp Klaus Krause on Sat May 30 02:04:00 2020
    Philipp Klaus Krause <pkk@spth.de> writes:

    Am 08.05.20 um 17:38 schrieb Tim Rentsch:

    For example, under this scheme, we might do this:

    // File "fs_string.h"

    #include <string-optional.h> // string.h optional subset

    #if ! _Provides_strlen
    extern size_t strlen( const char * );
    #endif

    ...

    // File "fs_string.c"

    #include "fs_string.h"

    #if ! _Provides_strlen
    size_t
    strlen( const char *s ){
    size_t r = 0;
    while( *s++ ) r++;
    return r;
    }

    #endif

    Now the rest of the program can simply #include "fs_string.h",
    and use strlen() just as it would if strlen() was supplied
    by the implementation.

    But this example also shows that it is relatively easy to implement
    strlen(), so there is not much burden on implementations when requiring
    them to provide it. And it shows that strlen not being mandatory for freestanding implementations results in lots of duplicated code in
    software projects that target these implementations.

    You already gave these arguments. They weren't convincing
    before, and repeating them doesn't make them any more
    convincing.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Philipp Klaus Krause@21:1/5 to All on Tue Aug 4 10:58:11 2020
    Am 08.05.20 um 17:38 schrieb Tim Rentsch:

    What I like about your idea is the notion that an interface is
    standardized, and an implementation gets a binary choice,
    either to provide it as specified, or just not to provide it.

    To make that idea work for case under discussion here (ie, for
    string functions), I think that needs to be augmented in two
    ways. One, it needs to be more fine grained than just all of
    <string.h>.

    The current C2X draft has __STDC_VERSION_XXXX_H__, which allows to
    specify the version of the standard a header conforms to. While not as fine-grained as a per-function macro would be, it already is much more fine-grained than the previously existing global macro for standard
    version compliance.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Keith Thompson@21:1/5 to Philipp Klaus Krause on Tue Aug 4 07:35:00 2020
    Philipp Klaus Krause <pkk@spth.de> writes:
    Am 08.05.20 um 17:38 schrieb Tim Rentsch:

    What I like about your idea is the notion that an interface is
    standardized, and an implementation gets a binary choice,
    either to provide it as specified, or just not to provide it.

    To make that idea work for case under discussion here (ie, for
    string functions), I think that needs to be augmented in two
    ways. One, it needs to be more fine grained than just all of
    <string.h>.

    The current C2X draft has __STDC_VERSION_XXXX_H__, which allows to
    specify the version of the standard a header conforms to. While not as fine-grained as a per-function macro would be, it already is much more fine-grained than the previously existing global macro for standard
    version compliance.

    It says:

    Some standard headers define or declare identifiers that had
    not been present in previous versions of this document. To
    allow implementations and users to adapt to that situation,
    they also define a version macro for feature test of the form
    __STDC_VERSION_XXXX_H__ which expands to yyyymmL, where XXXX
    is the all-caps spelling of the corresponding header <xxxx.h>.

    I wonder if it would make sense to require that macro for all standard
    headers rather than just the ones that have changed. (A counterargument
    is that a program wouldn't check the value unless the programmer knows
    that something has changed.)

    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    Working, but not speaking, for Philips Healthcare
    void Void(void) { Void(); } /* The recursive call of the void */

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)