The question I have is mostly related to section four, paragraph six.
The two forms of conforming implementation are hosted and freestanding. A conforming hosted implementation shall accept any strictly conforming program.
As I understand, this constitutes the typical application environment, with filesystems, allocated memory and threads...
A conforming freestanding implementation shall accept any strictly conforming program in which the use of the features specified in the library clause (clause 7) is confined to the contents of the standard headers
<float.h>
,<iso646.h>
,<limits.h>
,<stdalign.h>
,<stdarg.h>
,<stdbool.h>
,<stddef.h>
,<stdint.h>
, and<stdnoreturn.h>
.
... and this constitutes the typical kernel and/or embedded, bare minimum environment that doesn't have standard filesystems, allocated memory or threads (among other things).
A conforming implementation may have extensions (including additional library functions), provided they do not alter the behavior of any strictly conforming program.
It seems as though this gives a hosted implementation the freedom to call itself a hosted or freestanding implementation, and when it comes to filesystems, allocated memory or threads (among other things), these can fall under the extension category so that it can merely implement an interface that returns a value indicating errors every time. Just to name a few:
fopen
, fgets
and malloc
can return NULL
fprintf
, fscanf
, fputc
and fgetc
can return EOF
thrd_create
can return thrd_error
(indicating that "the request could not be honored")This implies that the distinction section four, paragraph six gives is virtually meaningless. Are there any requirements guaranteeing some actual level of functionality for these functions in hosted and freestanding implementations? For example, is it required that those functions above actually be able to return something other than their corresponding failure values?
Under a freestanding implementation, it is implementation-defined whether a program can have more than one thread of execution. Under a hosted implementation, a C++ program can have more than one thread running concurrently.
Informally, a hosted implementation is a C translation and execution environment running under an operating system with full support for the language and library.
The cited paragraph already states it quite well.
A hosted execution environment is also a freestanding, but not vice versa. A compiler need only provide a freestanding implementation. gcc, for example, is strictly speaking freestanding only, as the standard library is not included. However, it assumes it is available when compiling for a hosted environment (the default), assuming the lib is available on the system (like glibc). See here
Simply put, freestanding is just the language. It is not required to support any libraries and just a few headers (mostly for common types and implementation specific stuff like numerical limits, etc.). This implies the standard library need not exist - nor do the corresponding headers. Reason is a freestanding environment most likely will not have such facilities like files, display, etc. It is used for kernels, bare-metal embedded, etc.
Note that gcc for instance will, if compiling for a hosted environment (-fhosted
), assume functions used in the standard library have the corresponding meaning and might apply very aggressive optimizations (it has many of those functions built-in). For freestanding, it actually does not, so you can use a function strcmp
for instance with completely different semantics. However, it assumes the mem...-functions to exist, as these are used for normal code, e.g. struct assignment.
So, if building for bare-metal, you should always pass -ffreestanding
.
If a hosted implementation calls itself freestanding, it is obviously not a hosted implementation anymore. Once it calls itself hosted, however, it has to provide all facilities required by the standard and is not allowed to just implement dummies, but has to provide the semantics as defined in the standard.
Just to state that clear: The cited section allows a freestanding environment to omit all functions of the library, except for the few listed headers. So you are free to supply any other library and use the same names, but do anything you like. As that would be not the standard library, there is no need for compliance.
5.1.2.1 further states that "Any library facilities available to a freestanding program, other than the minimal set required by clause 4, are implementation-defined.". That does support my statement. Sidenote: It also does not require main()
as program entry point.
The hosted respectively freestanding implementations which the standard defines are minimal definitions. Both variants are the smallest common denominator of what can reasonably be implemented on a wide range of actual systems.
The rationale for defining such minimal, doable sets is to specify how a program targeting either one of the two flavors must look in order to compile and run with the expected result on ideally all implementations conforming to the respective flavor.
A program strictly conforming to the (i.e., to either) standard is maximally portable.
It goes without saying that actually existing implementations, both freestanding and hosted, typically provide a plethora of extensions, which is fine as far as the standard is concerned — with the one caveat that the extensions must not invalidate a strictly conforming program.
Back to your question: The distinction which the standard makes — the theory — is clear. Actually existing implementations — the practice — fall in a wide spectrum between and beyond the standard's minimal requirements but are bound to the "must not change the behavior" clause regarding strictly conforming programs (targeting hosted or freestanding implementations and not relying on any extensions).
By the way, your examples regarding standard library dummy functions is correct: For freestanding implementations these are just a funny case of allowed extensions: No strictly conforming program targeting freestanding environments would call them anyway. As part of a hosted environment they would be conforming but useless. (One can actually run into situations like that when certain system resources are exhausted, or they could be test stub implementations.)
There are many kinds of C implementations, targeting many kinds of different execution platforms, many of which can provide a variety of useful features and guarantees that others cannot. The authors of the Standard decided that in most cases it should be sufficiently obvious what kinds of features and guarantees should be provided by implementations targeting various platforms and application fields, and how they should be provided, that there would be no need to have a standard concern itself with such details. On the other hand, the number of applications that would require things like file I/O and the number of platforms that could provide them were sufficient to justify recognizing as "special" those implementations which included such features.
In general, implementations which are intended designed for freestanding use will be usable on platforms that would be unable to usefully handle a hosted implementation. While the Standard imposes some requirements beyond what would be practical on some of the smaller C platforms, some almost-conforming implementations of C can be quite usefully employed on processors with only enough storage to hold 256 instructions and 16 bytes' worth of variables. If something like a digital kitchen thermometer/timer gadget doesn't have a file system or console, why should it waste storage on things like descriptors for stdout?
In addition, because the Standard defines no standard means by which freestanding applications can perform I/O, and because different platforms handle I/O differently, almost freestanding applications will be targeted for a particular target platform or range of platforms. A hosted implementation which doesn't expose the natural features or guarantees the underlying platform would provide could be useful for running programs that don't require such features or guarantees. It's not possible for an embedded program to do much of anything without using platform-specific features and guarantees, however, and thus a freestanding implementation which didn't allow a programmer access to such things would be unable to do much. Quality implementations should allow programmers to use any features or guarantees that may help them accomplish what they need to do, though some may require use of compilation options to ensure that they don't do anything wacky. For some reason, it has become fashionable to regard a decision by the Standards Committee that there might be some implementations and application fields where the value of a feature or guarantee wouldn't justify the cost, as an indication that programmers should not expect implementations to provide a feature or guarantee which would be useful in low-level programming and which the platform would provide as essentially zero cost.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With