Computing > Programming

Design a better "C"

(1/57) > >>

Yeah I know this is a very recurring topic. But since we have talked a lot about C here, its strong points, and (very often) its shortcomings, I'm curious what you guys would propose for a "better C" language. Especially from the POV of people that are mostly EEs (and only a few of them are pure software guys, I think).

Syntax could be different. The key here would be to keep the essence of C: simplicity, portability, high-level and low-level enough, and the potential for wide acceptance. Meaning probably avoiding "uncomfortable" constructs or too exotic approaches, and, of course, making it usable on small embedded targets.

You can mention existing candidates (Rust comes to mind, but there are also attempts such as Zig and Odin, and lots of others...), but what would be interesting, instead of just mentioning them, would be to detail what you think is great in them for a C replacement, and what you think isn't that great. I'm sure many of you have considered alternatives over the years, and yet are still using C. So, getting to the bottom line of what would make this possible could be enlightening. Hopefully.

The final conclusion may very well be that there won't be a real replacement for C in areas it's used most these days. But some ideas could be interesting. Let's try not to turn this into a language war, it's just meant to be constructive.

No time now to get into the details.

But as you mentioned 'rust' is an interesting modern systems programming language.
Also 'go'.

So speaking mostly about what is modern and also oriented for system programming and also relatively popular those two have
the most relevance to me I think.

The main weakness of some other languages wrt. C I think is that some other languages require a certain combination of either a runtime environment (e.g. VM) or required system / language level libraries / APIs / features that may have a high space / ROM / RAM memory size cost on minimal embedded platforms.  Or some features may just not be available in certain platforms.
Things like complex formatted output / io functions, file system functions, networking functions, time keeping functions, multithreading functions, memory management functions, synchronization functions, memory model requirements, etc.

Then again with respect to the above modern C is really not so much better since its standard library does have memory management (malloc, ...), file system (fread, read), complex formatted IO (fprintf, ...), multithreading, etc. where those kinds of things may not be usable or possible on some very minimal platforms like a ARM cortex-m0 with 512 bytes of SRAM and 1KB of FLASH or whatever.

Another issue is machine architecture.  Most any modern language can fairly safely assume that it will run on a 32 bit platform with efficient 32 bit math and register and memory operations.  It might even be so bad of a constraint that 8 or 16 bit word size platforms don't work efficiently or at all for a given language / library model per. the strict standard requirements.

C is sort of flexible that way in that even a "byte" is sort of nebulously defined in size and other constructs pretty much require 16 bit word processing and/or possibly 32 or 64 bit processing but the requirements were originally very lax and if anything (IMHO) are an impediment today with respect to its flexibility.  Is the machine ones complement?  twos complement?  8-bit?  16-bit?  little endian?  some other endian?  floating-point?  ieee-754 FP?  Can you load / store from unaligned addresses and if so when / how?
So given all the architecture ambiguity it is actually HARD to write *truly* standards compliant portable system code in C because "in theory" you could then run on some other C language conforming platform with wildly different architecture and then your data representations are all totally unpredictably different.

So IMHO one should look at languages that can run on ARM cortex m or RISCV RV32I or something like that as a minimum sort of platform.  Integer operations.  32-bit words.  8/16 bit operations can be done somehow efficiently.  Flexible endianness.  IEEE754 floating point optional.  Multi-core optional.  64b native optional.  Assumption that you're writing typically for MCUs or better with at least 32kBy RAM so having some kind of "run time" or "library" overhead in the XX kBy range is at least potentially tolerable, particularly if "actually unused" parts are statically stripped out by the compiler / linker / system configuration / whatever.

Then you can at least talk about the idea of having some "higher level" runtime based environment like JVM / JAVA like or Erlang or using Rust / Go as a system programming language, or even some variant of python, lua, javascript, pascal, dart, scala, kotlin, whatever.

I guess to me the better question is "what could you use instead of C++" for embedded system programming since that usually implies at least XX kBy + XX MHz + 32-bit or better platform as opposed to trying to fill every niche down to MCUs that are almost better programmed in assembler because of their scant architectural capabilities.

As an EE, the main reason for choosing a particular language is having a compiler available for the microcontroller that you are using. Most manufacturers just provide a compiler that supports C and therefore Most of the projects in which I have worked are written in C, but if they just supported another language (C++, Ada, etc) I would use it. The language is not that important, as programs that run in microcontrollers are normally not that big and therefore it is easier to maintain them (although some projects even require running an embedded Linux distro in the MCU. One of my professors said to us that we shouldn’t try to invent a new way to write an if but something new to use it for, and I have followed that recommendation since then.

However, there are some things that make some languages nicer. Standardization improves portability and being able to write inline assembly routines is a must if you’re working with DSPs or control systems that operate in real time. Therefore, it would be nice if interruptions where included in the C standard, as each manufacturer uses a different way to specify which functions should be mapped to them. Being able to specify the location in which variable should be used (for mapping registers) without using linker scripts would also be useful, as Ada allows.

On the other hand, nowadays FPGAs allow implementing application specific processors quite easily, so being able to easily write a compiler backend for them might become same thing important in the near future when choosing a programming language

Finally, I wouldn’t use a language which is not ISO standardized, nor an interpreted one. The first ones tend to change too fast breaking the compatibility of old programs with new compilers and the second ones are too slow for these applications. JIT compilation should also be avoided in real time applications as well as garbage collectors as they impede predicting the amount of time that a function will require for being executed. Additionally, in some industries, just ISO standardized languages are allowed, which is something that also needs to be taken into account when choosing it

I wouldn't mind some basic C++ stuff. Just objects with inheritance. Perhaps overloading. Forget template stuff and pretty much everything else. Streams... well, if you must I suppose.

David Hess:
I would fix the problem of operations returning the wrong result size; real multipliers return a product which is  twice the size of the operands.  I would add fixed point radix tracking; bookkeeping is exactly what computers are good at.  Some old "improved" C compilers for DSP and embedded use did both of these.


[0] Message Index

[#] Next page

There was an error while thanking
Go to full version