Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Making more of the C standard library mandatory for freestanding implementations

69 views
Skip to first unread message

Philipp Klaus Krause

unread,
May 6, 2020, 12:19:33 PM5/6/20
to
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?

Philipp

Grant Edwards

unread,
May 6, 2020, 12:47:30 PM5/6/20
to
On 2020-05-06, Philipp Klaus Krause <p...@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.
>
> Should more of the standard library become mandatory for
> freestanding implementations?

No. Just No. For use on small embedded systems, there must be a
"bare metal" option that requires no standard library functions.

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

Memory size.

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

NONE. Freestanding, should remain freestanding. If you want to
define some "semi-hosted" spec, that's fine. Leave freestanding
alone.

--
Grant



Philipp Klaus Krause

unread,
May 6, 2020, 1:16:18 PM5/6/20
to
Am 06.05.20 um 18:47 schrieb Grant Edwards:
>>
>> Do you see any reason those could not be provided on some C
>> implementation?
>
> Memory size.

Could you elaborate?

I do not see a problem there: If the programmer doesn't use e.g.
memcpy(), no memcpy() will be linked in, so memory size would not be
affected. And if the programmer needs the functionality of memcpy(), I
don't see why using it would be worse than the programmer rollinghteir
own version.

Philipp

Grant Edwards

unread,
May 6, 2020, 2:10:43 PM5/6/20
to
On 2020-05-06, Philipp Klaus Krause <p...@spth.de> wrote:
> Am 06.05.20 um 18:47 schrieb Grant Edwards:
>>>
>>> Do you see any reason those could not be provided on some C
>>> implementation?
>>
>> Memory size.
>
> Could you elaborate?
>
> I do not see a problem there: If the programmer doesn't use e.g.
> memcpy(), no memcpy() will be linked in, so memory size would not be
> affected.

Would that be required by the spec?

--
Grant




James Kuyper

unread,
May 6, 2020, 3:10:46 PM5/6/20
to
No, but it might be required by the marketplace. If you had a choice of
two compilers, one of which always links in standard library routines
even if they're unused, and the other of which only links them in if
they are used, which one would you select, particularly if targeting a
platform with only limited memory? Do you think there's any significant
number of people who would choose differently?

Richard Damon

unread,
May 6, 2020, 4:08:21 PM5/6/20
to
By that same logic, people will chose the implementation that implement
more of the optional headers (or at least the ones they want) over those
that don't. There is nothing in the Standard to say that they can't
implement the part that aren't required.

Keith Thompson

unread,
May 6, 2020, 4:22:05 PM5/6/20
to
True. On the other hand, 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.

You probably wouldn't want to require that. For example, an
implementation might reasonably provide printf but not fprintf, or
provide printf but without floating-point support. It would be
difficult to define the requirements for partial support.

It's probably good enough that a freestanding implementation's
documentation can say something like "We support <stdio.h> as specified
by C11 with the following exceptions ...".

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

Philipp Klaus Krause

unread,
May 6, 2020, 4:34:19 PM5/6/20
to
Am 06.05.20 um 21:10 schrieb James Kuyper:
> On 5/6/20 2:10 PM, Grant Edwards wrote:
>> On 2020-05-06, Philipp Klaus Krause <p...@spth.de> wrote:
>>> Am 06.05.20 um 18:47 schrieb Grant Edwards:
>>>>>
>>>>> Do you see any reason those could not be provided on some C
>>>>> implementation?
>>>>
>>>> Memory size.
>>>
>>> Could you elaborate?
>>>
>>> I do not see a problem there: If the programmer doesn't use e.g.
>>> memcpy(), no memcpy() will be linked in, so memory size would not be
>>> affected.
>>
>> Would that be required by the spec?
>
> No, but it might be required by the marketplace. […]

While compilers exist, that cannot remove unused functions from
non-library user code (though such removal is now a common feature), I
do not know of any compilers that would link in the whole standard
library. All implementations known to me will only link in the used
parts of the standard library.

Philipp

Philipp Klaus Krause

unread,
May 6, 2020, 4:37:00 PM5/6/20
to
Am 06.05.20 um 22:08 schrieb Richard Damon:
>>
>> No, but it might be required by the marketplace. If you had a choice of
>> two compilers, one of which always links in standard library routines
>> even if they're unused, and the other of which only links them in if
>> they are used, which one would you select, particularly if targeting a
>> platform with only limited memory? Do you think there's any significant
>> number of people who would choose differently?
>>
>
> By that same logic, people will chose the implementation that implement
> more of the optional headers (or at least the ones they want) over those
> that don't. There is nothing in the Standard to say that they can't
> implement the part that aren't required.
>

Yes, but one benefit of standardization is providing a baseline of
functionality that C programmers can target.
This is somewhat different from optimization (such as not linkingunused
parts of the stadnard library).

Grant Edwards

unread,
May 6, 2020, 4:57:34 PM5/6/20
to
On 2020-05-06, Philipp Klaus Krause <p...@spth.de> wrote:

> Yes, but one benefit of standardization is providing a baseline of
> functionality that C programmers can target.

IMO, talking about a standardized baseline of library functionality
for bare-metal freestanding targets doesn't make much sense. In my
experience, freestanding projects tend to be very idiosyncratic.

--
Grant



Hans-Bernhard Bröker

unread,
May 6, 2020, 5:25:51 PM5/6/20
to
Am 06.05.2020 um 22:36 schrieb Philipp Klaus Krause:

> Yes, but one benefit of standardization is providing a baseline of
> functionality that C programmers can target.

And a baseline belongs exactly there: at the base of the building, i.e.
all the way down. At the bottom. And there can be only _one_ baseline.

We have names for the two relevant feature completeness levels: the
baseline is "freestanding", the top edge is "hosted", and IMHO that's
completely correct like that.

I very much doubt there's a need for more named levels. And even if
there were such a need, there's simply no way people would ever agree on
where, exactly, those levels should be. So in the end the number of
such level can be either be either 1, 2 or infinite.

Grant Edwards

unread,
May 6, 2020, 5:34:04 PM5/6/20
to
On 2020-05-06, Hans-Bernhard Bröker <HBBr...@t-online.de> wrote:

> Am 06.05.2020 um 22:36 schrieb Philipp Klaus Krause:
>
>> Yes, but one benefit of standardization is providing a baseline of
>> functionality that C programmers can target.
>
> [...]
>
> I very much doubt there's a need for more named levels. And even if
> there were such a need, there's simply no way people would ever
> agree on where, exactly, those levels should be.

The arguments about "printf" alone would take decades and cost
thousands of lives. :)

--
Grant


Richard Damon

unread,
May 6, 2020, 10:29:30 PM5/6/20
to
In fact, it is quite common to implement parts intentionally
'incorrectly', I have had many with a printf that totally omitted float
point formats because that support is EXPENSIVE (especially if that is
the only floating point code in the program).
>
> You probably wouldn't want to require that. For example, an
> implementation might reasonably provide printf but not fprintf, or
> provide printf but without floating-point support. It would be
> difficult to define the requirements for partial support.
>
> It's probably good enough that a freestanding implementation's
> documentation can say something like "We support <stdio.h> as specified
> by C11 with the following exceptions ...".
>

Yes, making the parts of the option headers supported be 'Implementation
Defined' might make sense.

upsid...@downunder.com

unread,
May 7, 2020, 2:00:01 AM5/7/20
to
On Wed, 6 May 2020 18:19:31 +0200, Philipp Klaus Krause <p...@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.

upsid...@downunder.com

unread,
May 7, 2020, 2:13:47 AM5/7/20
to
On Wed, 6 May 2020 22:34:16 +0200, Philipp Klaus Krause <p...@spth.de>
wrote:

>Am 06.05.20 um 21:10 schrieb James Kuyper:
>> On 5/6/20 2:10 PM, Grant Edwards wrote:
>>> On 2020-05-06, Philipp Klaus Krause <p...@spth.de> wrote:
>>>> Am 06.05.20 um 18:47 schrieb Grant Edwards:
>>>>>>
>>>>>> Do you see any reason those could not be provided on some C
>>>>>> implementation?
>>>>>
>>>>> Memory size.
>>>>
>>>> Could you elaborate?
>>>>
>>>> I do not see a problem there: If the programmer doesn't use e.g.
>>>> memcpy(), no memcpy() will be linked in, so memory size would not be
>>>> affected.
>>>
>>> Would that be required by the spec?
>>
>> No, but it might be required by the marketplace. […]
>
>While compilers exist, that cannot remove unused functions from
>non-library user code (though such removal is now a common feature), I
>do not know of any compilers that would link in the whole standard
>library. All implementations known to me will only link in the used
>parts of the standard library.

The standard practice for at least half a century has been to put only
a single library function into a source file and compile each module
separately.

In the most primitive form just add the names of the required library
object files at the end of the linker command line.

A more elaborate library systems put these object files into a single
library file, builds a symbol table for global functions defined in
each library module. When the linker has linked the user program and
there are still undefined external references, scan the library symbol
table to find which module defines the required global symbol. Then
seek() to the start of the module and read it in. If there are new
undefined symbols, repeat the library symbol table scan.


Philipp Klaus Krause

unread,
May 7, 2020, 4:16:45 AM5/7/20
to
Am 06.05.20 um 23:25 schrieb Hans-Bernhard Bröker:
> Am 06.05.2020 um 22:36 schrieb Philipp Klaus Krause:
>
>> Yes, but one benefit of standardization is providing a baseline of
>> functionality that C programmers can target.
>
> And a baseline belongs exactly there: at the base of the building, i.e.
> all the way down.  At the bottom.  And there can be only _one_ baseline.
>

Yes. And I am arguing that this baseline should include most of
string.h. The baseline should omit everything that is hard to implement
on some hardware (e.g. dynamic memory, I/O, certain minimum values for
implementation limits). But it should include stuff such as memcpy(),
that can be implemented on any hardware.

Philipp Klaus Krause

unread,
May 7, 2020, 4:18:00 AM5/7/20
to
Am 06.05.20 um 23:34 schrieb Grant Edwards:
I guess so. And I'm not arguing that printf() should be mandatory for
freestanding implementations. But I see quite some difference between
printf and memcpy.

Tim Rentsch

unread,
May 7, 2020, 9:08:37 AM5/7/20
to
Keith Thompson <Keith.S.T...@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.

Tim Rentsch

unread,
May 7, 2020, 9:14:50 AM5/7/20
to
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.

David Brown

unread,
May 7, 2020, 9:43:54 AM5/7/20
to
On 07/05/2020 04:29, Richard Damon wrote:
> On 5/6/20 4:22 PM, Keith Thompson wrote:
<snip>
>> You probably wouldn't want to require that. For example, an
>> implementation might reasonably provide printf but not fprintf, or
>> provide printf but without floating-point support. It would be
>> difficult to define the requirements for partial support.
>>
>> It's probably good enough that a freestanding implementation's
>> documentation can say something like "We support <stdio.h> as specified
>> by C11 with the following exceptions ...".
>>
>
> Yes, making the parts of the option headers supported be 'Implementation
> Defined' might make sense.
>

Indeed - "implementation defined" means it has to be properly documented.

Perhaps there could be wording to say that the optional headers (and
their associated functions) can be omitted for freestanding
implementations - but for each header that is provided, it must either
be fully conforming or document any limitations or changes.

Other than that, I don't see any need to make other parts of the library
non-optional. In practice, toolchains invariably implement all
functions that make sense on the target - they have abs(), and memcpy(),
and the like. But they might have non-conforming printf (as mentioned
already), and typically omit file-related functions and wide character
functions on smaller systems.

I can't see an issue with portability, as you simply don't expect to be
able to use code with file handling on a device with no file system, or
wide characters on a system with no display.

Tauno Voipio

unread,
May 7, 2020, 11:45:24 AM5/7/20
to
printf() is a can of worms in a bare-metal environment.
If it is implemented in the standard way, it needs the
whole kit and caboodle of standard I/O, including dynamic
memory allocation. It is luxury that does not fit into a
small embedded device.

--

-TV

Tauno Voipio

unread,
May 7, 2020, 11:47:33 AM5/7/20
to
The shared/dynamic libraries contain all the functions with
their entry points listed separately.

--

-TV

Grant Edwards

unread,
May 7, 2020, 11:51:19 AM5/7/20
to
On 2020-05-07, Tauno Voipio <tauno....@notused.fi.invalid> wrote:

> The shared/dynamic libraries contain all the functions with
> their entry points listed separately.

I've never seen a freestanding target that had shared/dynamic
libraries. All of the freestanding targets I've ever worked with ran
as a single statically linked binary executable.

--
Grant


Philipp Klaus Krause

unread,
May 7, 2020, 3:38:04 PM5/7/20
to
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.

Hans-Bernhard Bröker

unread,
May 7, 2020, 3:39:35 PM5/7/20
to
Am 07.05.2020 um 10:16 schrieb Philipp Klaus Krause:
> Am 06.05.20 um 23:25 schrieb Hans-Bernhard Bröker:
>> Am 06.05.2020 um 22:36 schrieb Philipp Klaus Krause:
>>
>>> Yes, but one benefit of standardization is providing a baseline of
>>> functionality that C programmers can target.
>>
>> And a baseline belongs exactly there: at the base of the building, i.e.
>> all the way down.  At the bottom.  And there can be only _one_ baseline.
>>
>
> Yes. And I am arguing that this baseline should include most of
> string.h.

Why do you say "yes", and then immediately go on by stating the exact
opposite of what you just agreed to?

Anything that's not absolutely necessary doesn't belong in the baseline.
Otherwise it's something else, but not the baseline.

Philipp Klaus Krause

unread,
May 7, 2020, 3:44:41 PM5/7/20
to
Am 07.05.20 um 21:39 schrieb Hans-Bernhard Bröker:
I meant yes to having only one baseline. However I argue that the line
should not be drawn at an arbitrary point (why draw it between a large
part of the language and the library, rather than somewhere within the
language or the library?). IMO, the line should be drawn based on what
can be easily implemented on virtually all hardware.

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.

Paul Rubin

unread,
May 7, 2020, 3:54:53 PM5/7/20
to
Philipp Klaus Krause <p...@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.

Tauno Voipio

unread,
May 8, 2020, 3:09:39 AM5/8/20
to
Neither have I. Just mentioned it to keep the shared libraries
out of the discussion.

I even use the options in GNU toolset to drop unused functions
at linking stage.

For bare metal, I have needed to recompile the newlib-arm
with size optimization (-Os) to keep the resulting binary
at a minimum size.

--

-TV


Tim Rentsch

unread,
May 8, 2020, 11:38:28 AM5/8/20
to
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.

Florian Weimer

unread,
May 8, 2020, 12:48:35 PM5/8/20
to
* Grant Edwards:

> On 2020-05-06, Philipp Klaus Krause <p...@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.
>>
>> Should more of the standard library become mandatory for
>> freestanding implementations?
>
> No. Just No. For use on small embedded systems, there must be a
> "bare metal" option that requires no standard library functions.

Why? Why would the link editor copy unreferenced functions in the
standard library?

My concern would that an implementation that takes this proposal
seriously would make it impossible to test different implementations
of these functions without patching the language implementation itself
(rather just overriding the functions). So language implementations
would likely continue to provide something like -ffreestanding.

Andrew Smallshaw

unread,
May 8, 2020, 1:01:52 PM5/8/20
to
On 2020-05-08, Florian Weimer <f...@deneb.enyo.de> wrote:
> * Grant Edwards:
>
>> On 2020-05-06, Philipp Klaus Krause <p...@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.
>>>
>>> Should more of the standard library become mandatory for
>>> freestanding implementations?
>>
>> No. Just No. For use on small embedded systems, there must be a
>> "bare metal" option that requires no standard library functions.
>
> Why? Why would the link editor copy unreferenced functions in the
> standard library?

Some small embedded systems have no support for a linker of any
kind - assembly inevitably proceeds to an exectuable. It was more
common on older systems but you still see it on oddball architectures
and "research quality" (it this context that means rough and ready)
development tools.

--
Andrew Smallshaw
and...@sdf.org

Philipp Klaus Krause

unread,
May 8, 2020, 2:06:02 PM5/8/20
to
Am 08.05.20 um 19:01 schrieb Andrew Smallshaw:
>>
>> Why? Why would the link editor copy unreferenced functions in the
>> standard library?
>
> Some small embedded systems have no support for a linker of any
> kind - assembly inevitably proceeds to an exectuable. It was more
> common on older systems but you still see it on oddball architectures
> and "research quality" (it this context that means rough and ready)
> development tools.
>

Can you give an example of a C99, C11 or C17 implementation of this
type? Clearly, this would be a limitation of the implementation, not of
the targeted hardware.

Tim Rentsch

unread,
May 8, 2020, 3:03:32 PM5/8/20
to
Philipp Klaus Krause <p...@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.

Philipp Klaus Krause

unread,
May 8, 2020, 3:15:42 PM5/8/20
to
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.

Philipp Klaus Krause

unread,
May 8, 2020, 3:27:53 PM5/8/20
to
Am 08.05.20 um 21:03 schrieb Tim Rentsch:
> Philipp Klaus Krause <p...@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).

Philipp Klaus Krause

unread,
May 8, 2020, 3:30:13 PM5/8/20
to
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.

David Brown

unread,
May 8, 2020, 6:25:37 PM5/8/20
to
On 08/05/2020 21:03, Tim Rentsch wrote:
> Philipp Klaus Krause <p...@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.

Jakob Bohm

unread,
May 15, 2020, 9:13:08 AM5/15/20
to
On 2020-05-08 21:27, Philipp Klaus Krause wrote:
> Am 08.05.20 um 21:03 schrieb Tim Rentsch:
>> Philipp Klaus Krause <p...@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

Tim Rentsch

unread,
May 30, 2020, 5:04:02 AM5/30/20
to
Philipp Klaus Krause <p...@spth.de> writes:

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

Philipp Klaus Krause

unread,
Aug 4, 2020, 4:58:13 AM8/4/20
to
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.

Keith Thompson

unread,
Aug 4, 2020, 10:35:02 AM8/4/20
to
Philipp Klaus Krause <p...@spth.de> writes:
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.T...@gmail.com
Working, but not speaking, for Philips Healthcare
void Void(void) { Void(); } /* The recursive call of the void */
0 new messages