apache / nuttx

Apache NuttX is a mature, real-time embedded operating system (RTOS)
https://nuttx.apache.org/
Apache License 2.0
2.85k stars 1.17k forks source link

Reevaluate the C89 Requirement #6896

Open AlanRosenthal opened 2 years ago

AlanRosenthal commented 2 years ago

The C Coding Standard states:

C Style Comments. C99/C11/C++ style comments (beginning with //) should not be used with NuttX. NuttX generally follows C89 and all code outside of architecture specific directories must be compatible with C89.

However, trying to compile NuttX with the gcc flag -std=c89 results in many compiler errors.

For example, take this file: include/nuttx/list.h It uses the inline keyword, which is not a c89 feature: https://stackoverflow.com/questions/12151168/does-ansi-c-not-know-the-inline-keyword

Also see: https://gcc.gnu.org/onlinedocs/gcc/C-Dialect-Options.html

This turns off certain features of GCC that are incompatible with ISO C90 (when compiling C code), or of standard C++ (when compiling C++ code), such as the asm and typeof keywords, and predefined macros such as unix and vax that identify the type of system you are using. It also enables the undesirable and rarely used ISO trigraph feature. For the C compiler, it disables recognition of C++ style ‘//’ comments as well as the inline keyword.

The alternate keywords __asm__, __extension__, __inline__ and __typeof__ continue to work despite -ansi. You would not want to use them in an ISO C program, of course, but it is useful to put them in header files that might be included in compilations done with -ansi. Alternate predefined macros such as __unix__ and __vax__ are also available, with or without -ansi.

Since NuttX currently uses the inline keyword, it makes sense to reevaluate the C89 requirement.

Changing to C99/C11 gives access to many useful language features such as function pointers, _Bool (https://github.com/apache/incubator-nuttx/blob/master/include/stdbool.h#L64-L67), __func__ macro, stdatomic, single line comments, and many other features. See https://cw.fel.cvut.cz/old/_media/courses/be5b99cpl/lectures/be5b99cpl-lec10-handout-3x3.pdf for a large list of other changes.

xiaoxiang781216 commented 2 years ago

Yes, I agree that C89 is too old and not perfect(miss many important feature/patch). C99 is a better baseline that we should follow. Since it's a big decision, it's better to post the discussion to dev@nuttx.apache.org to get more attention.

AlanRosenthal commented 2 years ago

Thanks, I'll send this to the mailing list.

robertlipe commented 2 years ago

I raised this issue a while back. The argument that even // comments were evil rang hollow as git history showed they've been there for years, unnoticed. While I'm sure the Z80 development isn't exactly a hotbed, if they can't keep up with modern tools, you can't let them hold back your project forever.

// comments may be considered eye candy, but it's a poke in the eye to submit code and have it rejected because some OTHER system hasn't been updated in 23 years. It's a cognitive load on contributors. Likewise for in-place declarations - decls can be down in the function body near where they're used to reduce cognitive load of the artificial separation, just like having the decl inside loops.

_Bool is useful. true and false are just natural to read and write.

Most programmers today can't remember inline NOT being part of the language.

'long long' is useful for implementing file sizes and offset. On a $4 16GB SD card, supporting only 4GB files because you can't use long long is a problem.

Vararg macros makes complicated macros less painful. (Arguments that there shouldn't BE complicated macros are a different argument. Marshalling and serializing independent components is very much a thing in embedded.

designated initializers improve the readability of structure initializers and variable-length arrays are a very natural way to express things like a buffer coming out of a packet. bufsz = foo.size; char foobuf[bufsz]; strncpy(foo.data; bufsz, boobuf); gcc has had an extension that offered a similar extension for years.

stdint.h gives standardized names for a 16-bit thing or an 'at least 16-bit' thing. Let the programmer use the names they've spent decades using instead of a Nuttx-specific abstraction. Bonus that you can rely on the printf specifiers for the same.

aligned_alloc, alignof(), and alignas() are all things we've had to implement from scratch; let's instead use the standardized versions.

restrict allows better optimizing by proving that two pointers can't alias.

standardized atomics and accessors. No more rolling your own in machine/arch_atomic.c and such; use the ones provided by the host tools.

**standardized threads! It's mostly POSIX threads, but with annoyingly different names. Still, it's more reflexive to use something familiar than learn another. Itself that might not bring much to nuttx, but forced other useful changes like and _thread_local.

Unicode support. There can be substantial library work to provide this (likely already done elsewhere) but allowing const char* pi = '\u030C'; is pretty useful.

_Static_assert allows readable, standardized, sanity checks.

You don't have to go nuts and use everything. Some features can be easily misused in systems-level context. (VLAs, for example, may be sneaky about malloc calls. VLAs are generally contentious.) The opportunity for misuse similarly exists in C89 today. But the world wouldn't collapse (and would be less off-putting to contemporary programmers) if you quit forbidding //, stdint, stdbool, long long, in-body decls, designated initializer and a few of the others that shouldn't be contentious. It would substantially reduce the cognitive load for developers that aren't Nuttx-exclusive and that have programmed in C or C++ in the post-Hammer Pants era.

Most of the C11 work was finished in the GNU ecosystem years ago. https://gcc.gnu.org/wiki/C11Status. C17 is almost entirely bugfixes to C17 and generally not even considered a unique language.

The C language moves slowly. We've only had four versions of it since it's existed and the version discussed here is already 11 years old. C11/C17 is a very reasonable target. Maybe that means the 6502 port can't stay on current Nuttx forever, but they can't expect new features in an OS forever if there's no contemporary tooling available for them. Even GCC drops target from time to time as the cost to support them outweighs the benefits of moving on.

C17 is mostly a bugfix to C11, like nailing down realloc(NULL) and formalizing #elif. It's not even considered a version of its own. It's "a fixed C11"

You don't have to replace everything in the project to use C17 out of the gate. Just quit blocking PRs with a // comment or a _Static_assert or a _Bool or such.

Reducing programmer disorientation by requiring a 33 year old dialect of a language will help attract new devs. C and Embedded are already scary. Please make it more welcoming by not requiring a version of C older than many potential contributors.

I'll even try to help solve any issues with C17 that may arise if this is closed 'accepted'.

xiaoxiang781216 commented 2 years ago

Add the discussion thread: https://www.mail-archive.com/dev@nuttx.apache.org/msg08214.html

robertlipe commented 2 years ago

It's often mentioned that the most humble, actively developed, compiler still in use is SDCC. I just stumbled across their web page for another project and the first sentence says, "SDCC is a retargettable, optimizing Standard C (ANSI C89, ISO C99, ISO C11) " That covers 8031, 8051, Z80, and many other relics.

So even SDCC supports C11. Enabling use of C11 (at least not flat out rejecting incremental use of it) would bring a huge list of benefits, including not alienating a generation of programmers making them use a language that may be older than they are.

I get that C17 might be too radical. Raising the floor to C11 doesn't seem like crazy talk and would bring nice programmer conveniences. We left behind K&R once. (It was relevant for 11 years.) We can leave C89, too, since its first replacement is 23 years old. :-)