2

我正在研究通过 C 编译实现高级(类 Lisp)语言的可能性(或者如果异常证明足够有用,则可能是 C++);这是许多项目以前使用的策略。当然,这将生成 C 代码,这与您手工编写的任何内容不同,并且可能在某些方面超出了复杂性。

现代 C 编译器在正常使用中非常可靠,但很难知道在异常压力下的边缘情况下可能潜伏着哪些错误,特别是如果你超过了一些“没有程序员会写出大于 Y 的 X”的隐藏限制。

我突然想到,这些事实的巧合可能会导致不快乐。

是否有任何已知的案例,或者是否有一种很好的方法可以找到在合理的最新版本的主要编译器(例如 GCC、Microsoft C++、Clang)中生成的代码超出边缘案例错误/限制的案例?

4

4 回答 4

1

简短的回答:

如果您需要编译器的性能而不是解释器(或预编译器 + 解释器)的易用性,那么您别无选择。您将编译成一些较低级别的语言,而 C 是当今的汇编语言,C++ 与 C 一样可用且适用于该任务。您没有理由害怕这条路线。实际上,从某种意义上说,这是一条非常常见的路线。

长答案:

生成的代码绝不是不寻常的。即使是相对适度地使用生成的代码,也会导致 C 源代码“不同于任何程序员所编写的”,无论是在数量(微小的变化重复数百万次的琐碎代码模式)或质量(一个人类永远不会使用,但仍然是合法的 C++)。还有相当多的编译器可以编译成 C 或 C++,其中一些是编写 C 和 C++ 语言标准的人所熟知的。

最常见的 C 和 C++ 编译器可以很好地处理生成的代码。是的,它们从来都不是完美的。

  • 编译器可能有各种简单的限制,例如最大代码行长度;一旦你遇到它们,它们往往会被记录在案,并且很容易在你的生成器中遵守。
  • 编译器可能有缺陷。
    • 与手写代码相比,某些类型的缺陷实际上对于生成的代码来说并不那么令人担忧。一旦你开始理解模式并关心问题,你的代码生成器实际上给了你一定程度的自由来系统地处理许多情况。
    • 只要有足够多的编译器用户,就会很快发现实际上导致编译器无法正确编译有效代码的缺陷。它们被编译器供应商视为特别​​高优先级的缺陷。即使编译器本质上已经死了或服务于一个利基市场,因此没有可用的修复程序,互联网上往往会提供大量信息,包括人们解决缺陷的现有经验(不同的编译器,不同的代码构造,不同的编译器)开关......解决方案变化很大,可能会让人感到尴尬,但没有人会因为某些软件有问题而放弃他们的工作,对吧)?因此,通常可以选择可搜索的解决方案。

争取跨编译器的可移植性通常是件好事,但也要了解和跟踪可移植性的限制。如果您没有很好地测试过特定的 C 或 C++ 编译器,请不要声称它可以作为工具集的一部分工作。

您在问 C 和 C++ 之间的隐含问题。好吧,这里有更多的灰色阴影。C++ 是一种非常丰富的语言。您可以在生成器中将几乎所有 C++ 功能用于良好的目的,但在某些情况下,您应该问自己一个特定的主要功能是否会成为一种负担,从而使您付出的代价比它给您带来的更多。例如,不同的编译器使用不同的模板实例化策略。隐式实例化可能会导致可移植生成代码的不可预见的复杂性。如果模板确实可以极大地帮助您设计生成器,请不要犹豫使用它们;但是,如果您对它们只有一个边缘用例,请记住,您比大多数人有更好的理由来限制您生成的语言。

于 2013-05-08T20:42:46.507 回答
1

这可能不是您要寻找的答案,但几年前,我参与了一个项目,其中系统的某些部分是用某种更高级的语言编写的,在这个项目中很容易在进程中构建状态机。这种语言产生的 C 代码然后被编译。我们用于这个项目的编译器是 gcc(2.95 左右的版本——不要引用我的话,但肯定是 3.0 之前的版本)。我们确实遇到了几个代码生成错误,但从我的记忆来看,这更多地与使用不那么流行的处理器有关[揭示哪个处理器可能会揭示我不应该对项目进行的一些事情,所以我宁愿不说它是什么,即使是很久以前]。

我身边的一位同事正在调查其中一个代码生成错误,它在一个大约 200k 行的函数中,所有的函数都是一个大的 switch 语句,switch 语句中的每个 case 每个大约 50-1000 行(带有里面有几层子switch语句)。

根据我对它的记忆,代码崩溃是因为它产生了无效操作或将某些内容存储在已经被其他内容占用的寄存器中,所以一旦你找到正确的代码位,它就会由于非法的内存访问而失败 - 而且它与代码的长大小无关,因为我的同事最终设法将其减少到大约 30 行代码(经过很多“让我们把它删掉,看看它是否仍然出错”),并且经过几天后,我们有了一个带有修复程序的新版本的编译器。很高兴知道您为编译器服务合同支付的数千美元至少有时值得拥有......

我的观点是现代编译器可以容忍很多大代码。还有“兼容的编译器必须至少支持”的最低限制。例如,我相信(再次从记忆中)编译器需要在一个函数中支持 127 级嵌套语句(即 127 个 if、switch、while 和 do-while 的组合)。而且,从某处的讨论中(这是“编译器应该支持 127 级嵌套语句”的来源),我们发现 MSVC 和 GCC 都支持更多(足以让我们放弃寻找它...... )

于 2013-05-08T20:51:24.383 回答
1

C 中有各种实现定义的限制。一些定义明确且对程序员可见(想想数字限制),而另一些则不是。在我的标准草案副本中,第 5.2.4.1 节详细说明了这些限制的下限:

5.2.4 环境限制

翻译和执行环境都限制了语言翻译器和库的实现。下面总结了符合实现的与语言相关的环境限制;与图书馆相关的限制在第 7 节中讨论。

5.2.4.1 翻译限制

实现应能够翻译和执行至少一个程序,该程序包含以下每个限制的至少一个实例:18)
— 127 个块
嵌套级别 — 63 个条件包含嵌套级别
— 12 个指针、数组和函数声明符(以任何组合形式)修改声明中的算术、结构、联合或 void 类型
[...]


18) 实施应尽可能避免施加固定的翻译限制。

我不能确定您的翻译器是否可能会遇到这些问题,或者即使您这样做,您所针对的 C 编译器是否也会出现问题,但我认为您可能会没事的。

至于错误:

Clang - http://llvm.org/bugs/buglist.cgi?bug_status= all &product=clang
GCC - http://gcc.gnu.org/bugzilla/buglist.cgi?bug_status= all &product=gcc
Visual Studio - https ://connect.microsoft.com/VisualStudio/feedback

于 2013-05-08T20:54:50.223 回答
0

这听起来很明显,但真正知道的唯一方法是通过测试。如果你不能自己做所有的努力,至少让你的产品跨平台,以便人们可以轻松地为你测试!如果人们喜欢您的项目,他们通常愿意免费提交错误报告甚至补丁 :)

于 2013-05-08T19:09:30.893 回答