3 ms·
There is 'printf'. It's just that printf (and the rest of the standard library) is technically as much a part of the C language as the language grammar itself,
by monocasa 5y ago
There is 'printf'. It's just that printf (and the rest of the standard library) is technically as much a part of the C language as the language grammar itself, and C compilers are welcome to use innate knowledge of those functions for optimizations. The other place you typically see this is calls to functions like memcpy/memset being elided to inline vector ops or CISC copies, or on simpler systems, large manual zeroing and copying being elided the other way to a memset or memcpy call.
C compilers will typically have an escape hatch for envs like deeply embedded systems and kernels like gcc's -ffreestanding and -fno-builtin that says "but for real though, don't assume std lib functions exist or you know what they are based on the function's name".
<rust_task_force> One of my favorite parts of rust as someone who uses it for deeply embedded systems is the separation of core and std (where core is the subset of std that only requires memcpy, memset, and one other I'm forgetting). The rest of the standard library is ultimately an optional part of the language with compiler optimizations focused on general benefits rather than knowing at the complier how something like printf works. no_std is such a nicer env than the half done ports of newlib or pdclib that everyone uses in C embedded land.
</rust_task_force>
- deleted 5y ago[deleted]
- matheusmoreira 5y ago> C compilers will typically have an escape hatch for envs like deeply embedded systems and kernels like gcc's -ffreestanding and -fno-builtin that says "but for real though, don't assume std lib functions exist or you know what they are based on the function's name". GCC requires standard library functions even on freestanding environments! It will still emit calls to those functions in certain circumstances. https://gcc.gnu.org/onlinedocs/gcc/Standards.html https://gcc.gnu.org/onlinedocs/gcc/Standards.html > GCC requires the freestanding environment provide memcpy, memmove, memset and memcmp. > if __builtin_trap is used, and the target does not implement the trap pattern, then GCC emits a call to abort.
- quietbritishjim 5y agoThis comment isn't meant to disagree with what you said but is more like a related ramble. At least in C++, memcpy is special because it can be used to reinterpret bits of one object as another (in C you can use a union, and as of C++20 you can use the std::bit_cast function but it either just calls memcpy or it still needs its own magic) double d = 1.0; // type punning with union, allowed in C but not C++ union { double d; int64_t i; } u; u.d = d; int64_t y1 = u.i; // undefined behaviour // cast not allowed, not even reinterpret_cast int64_t y2 = *reinterpret_cast<int64_t*>(&x.d); // undefined behaviour // memcpy - allowed! (if sizeof() params is the same) int64_t y3; static_assert(sizeof(y3) == sizeof(d)); memcpy(&y3, &d, sizeof(y3)); // well defined! // C++20 bit_cast (probably just a convenience wrapper around memcpy) int64_t y4 = std::bit_cast<int64_t>(d); // well defined It seems wasteful to create a separate object in memory and copy bits from an old object, when all you want to do is reinterpret the bits of the existing chunk of memory. But memcpy doesn't do that (or at least might not) because it's optimised into a simple cast under the hood, but without the undefined behaviour. So memcpy looks like a standard library function but in a way it's more like a compiler instrinic. It would be possible to create a fully conformant version of memcpy, even in C++, by casting both parameters to char* which is special with respect to the aliasing rules, and copying char-by-char. But I suppose that would be harder to optimise into a simple cast.
- matheusmoreira 5y agoWhat a pain, right? Why can't they just let us do what they know we want to do? It's such an absurd situation. We have double precision floating point numbers. Sometimes we want to look at the bits. Sometimes we want to modify those bits. Would it kill them to let us cast the thing? I will never understand this.
- mid-kid 5y agoThe requirements for memcpy, memmove, memset and memcmp stem from the fact that statements like "char arr[100] = {0};" or "struct somestruct some_a = some_b;" cause implicit memsets and memcpys, in cases where it can't be handled within less instructions. These functions are required by the freestanding part of the C standard, too, anyway.
- ncmncm 5y agoThe "no_std" idea is one that has washed up over and over again, over the last half-century. ISO Standards typically call it "freestanding". It has invariably failed to yield the promised benefits. It hangs around, anyway, cluttering up Standards. People waste endless hours proposing alterations to it for the next Standard edition, to be likewise ignored by implementers and informed users of whichever language. I don't doubt that "no_std" will similarly float along, and even be taken up into whichever Standard takes hold, but it must identically fail to deliver to actual system developers, in practically useful terms, whatever benefit its promoters promise. A mirage may be beautiful, but it does not slake thirst.
- masklinn 5y agono_std is already in ubiquitous use in the embedded rust community and does exactly what it says on the tin. Having a no_std feature is extremely common to allow (restricted) crate use in that context.