How would a better C look like? This means to adhere to the spirit of C, but avoiding design mistakes.
Performance
Usually, C will be the fastest language in any benchmark. However, there are ways to become faster than C. Specifically, compile time evaluation is well known from C++. It requires meta programming mechanisms, which the C preprocessor does not provide. Most prominently, C's qsort function cannot inline the comparison operation, while C++'s std::sort can. This means a function call within an inner loop, which cannot be optimized.
A module system can improve compilation speed.
Some desirable features are available for C by compiler extensions,
e.g. GCC's #pragma once
.
Additionally, the concept of a compilation unit can be changed,
to enable cross module optimizations.
Productivity
Meta programming was already mentioned, but it also has the potential to improve productivity, since it enables more code reuse.
A solid module system liberates the programmer from keeping header files in sync. Likewise, the need for forward declarations can be removed. The prefixing of symbol names can be automated.
By cleaning up the syntax, compilation times and tool support can be improved. For example, refactoring can be done like in Java.
Common third-party tools should be more integrated. API documentation generation, unittesting, formatting, refactoring, bindings can be provided out of the box. By making it as easy as possible, the programmer is encouraged to actually use these tools.
Safety
Most important, safety can be improved. This is a tradeoff against the spirit of C mantra "trust the programmer". Type systems are primarily a mechanism to prevent the programmer from doing certain things.
Ultimately, a language with inline assembly and manual memory management cannot be completely typesafe. The programmer is free to break it at will. The trick is provide clear boundaries and get most of the code into the typesafe parts.
Once again meta programming comes up. Since type-safe generic containers and algorithms can be reused, the line count and the bugs should decrease.
Undefined behavior can be minimized. For example, C supports architectures where a byte is bigger than 8bits, but nowadays no such architectures exist anymore. The builtin types int and co are defined by the architecture, while this is sometimes convenient, the default types should be fixed like in Java.
Better defaults can be defined. For example, local variables and arguments can be const by default. Variables can initialized by default values instead of undefined values.
Maintaining the Strengths
Probably the biggest challenge of designing a better C is to maintain the strengths of C. For example, people like Linus Torvalds like that C does not allow operator overloading, since it avoids surprises of code behavior. However, meta programming like this enables a lot of good stuff as described above.
C++ is not a bad attempt for a better C. It has templates. However, the (not really) module system is the same.