虽说标准C语言持续在演进着当下版本是C23但依旧存在一些让人难以理解的缺陷没能修复。之前呢Dlang社区在它的D编程语言编译器里嵌入了一个全新的C编译器名为ImportC。通过支持 C 代码编译的https://dlang.org/spec/importc.html这一全新构建而成的编译器运用了现代编译技术解决了部分传统 C 的问题。问题来了为什么标准 C 语言没有修复这些缺陷譬如常量表达式的评估来看以下 C 代码示例int sum(int a, int b) { return a b; }enum E { A 3, B 4, C sum(5, 6) };使用 gcc 编译时会报错gcc -c test.ctest.c:3:20: error: enumerator value for C is not an integer constantenum E { A 3, B, C sum(5, 6) };^简单来讲尽管C语言借助常量折叠也就是Constant Folding能够于编译之际算出一个简易的表达式可它没办法在编译的时候去执行函数调用。然而ImportC是能够达成这一点的。建议改进于C语言语法里但凡能够运用常量表达式的地方编译器皆理应能够于编译之际执行函数只要这些函数不牵涉诸如I/O操作、访问可变的全局变量、开展系统调用等行为。编译时单元测试一旦C 编译器具备了编译时函数求值也就是 CTFE 的能力许多新功能就变得可能。在C代码里头单元测试是很少能瞅见的缘由十分简单它得在构建系统内单独去设置目标还要以独立的可执行文件方式来运行。这般额外的复杂性致使开发者常常把它给忽略掉。说不定你是个每天都坚持晨跑且认真设定单元测试场景的人呢可大多数开发者并非这般。例如int sum(int a, int b) { return a b; }_Static_assert(sum(3, 4) 7, test #1);使用 gcc 编译时会报错gcc -c test.ctest.c:3:16: error: expression in static assertion is not constant_Static_assert(sum(3, 4) 7, test #1);^然而ImportC 可以成功编译这段代码。潜在改进凭借允许于编译之际运行函数的方式C语言能够轻易达成单元测试功能。不需要额外的构建步骤也无需独立的测试可执行文件且每次代码编译之时单元测试都会自行运行。举例来说在ImportC的测试框架里头此种编译时测试获得了广泛应用。前向引用声明的问题C语言里函数的前向引用是一种常见的限定下面这段代码出示了这个问题int floo(int a, char *s) { return dex(s, a); }char dex(char *s, int i) { return s[i]; }使用 gcc 编译时会报错gcc -c test.ctest.c:4:6: error: conflicting types for dexchar dex(char *s, int i) { return s[i]; }^test.c:2:35: note: previous implicit declaration of dex was hereint floo(int a, char *s) { return dex(s, a); }原因在于错误就是编译器在解析floo之际针对dex的类型作了一个隐式的假设一般而言假设返回值是int然而实际所定义的类型跟此假设并不相符。要是把floo与dex的顺序颠倒过来那么这段代码便能够正常编译。这表明C编译器仅仅能够识别代码里“词法顺序上处于之前位置的声明”并且前向引用也就是在定义之前调用函数是不被准许的。为什么这是一个问题作为由于用以支持前向引用的缘故每一个函数均需具备一个明晰的声明举例来说char dex(char *s, int i); // 声明int floo(int a, char *s) { return dex(s, a); }char dex(char *s, int i) { return s[i]; } // 定义这种声明和定义的分离增加了无意义的工作量。其次这种限制致使开发者对代码顺序作出调整比如说会把叶子函数也就是底层函数放置在最靠前的位置然而全局接口函数则被置于最后面。这样的代码组织形式类似于从报纸的底部起始进行阅读是极为不符合直觉的。ImportC 能够准许在任意的顺序当中去编译全局声明换而言之呢开发者是不需要去忧虑函数定义的前后顺序方面的问题的。导入声明问题于传统C编程里头当处理多个文件模块之际一般而言是要单独去创建.h头文件用来声明模块接口了。以下这个示例呈现出了常见的文件结构。// floo.c#include dex.hint floo(int a, char *s) { return dex(s, a); }// dex.hchar dex(char *s, int i);// dex.c#include dex.hchar dex(char *s, int i) { return s[i]; }问题点1.繁复每一个外部模块均诉求一个独自专门的.h文件这般状况增添了从事开发工作人员的担负。2.容易出错要是.h文件的声明跟.c文件的定义并非完全匹配那么会致使各种各样的难以排查的错误出现。于ImportC里径直将模块有关的源文件予以导入就行并不需要额外来一些头文件哎。举例来说呢// floo.c__import dex;int floo(int a, char *s) { return dexx(s, a); }// dex.cchar dexx(char *s, int i) { return s[i]; }凭借这样的途径开发者压根儿无需去编写那 .h 文件消除掉了繁杂繁琐的声明事宜与此同时还降低了潜藏着的错误风险。