如何将C++代码转换为C

54

我有一些C++代码。在代码中有许多定义的类、成员函数、构造函数、析构函数,几个模板类和大量的C++代码。现在我需要将源代码转换为纯C代码。

我有以下问题:

  1. 有没有工具可以将C++代码和头文件转换为C代码?

  2. 我是否必须对代码进行全面重写(我将不得不删除构造函数、析构函数并将该代码移动到某些 init()deinit() 函数中;将类更改为结构体,在新定义的结构体中将现有成员函数作为函数指针,并使用函数指针调用这些函数等)?

  3. 如果我必须手动进行转换,那么我需要注意哪些C++特定的代码数据结构/语义,在从C++转换为C时需要注意什么?

6个回答

33

确实有这样一个工具,叫做 Comeau 的 C++ 编译器。它会生成一些 C 代码,但你无法手动维护它们,不过这也没关系。你可以继续维护 C++ 代码,并且在运行时将其转换成 C 代码。


1
@MSalters:感谢您提供有关Comeaus编译器的指针。但遗憾的是,这不符合我的目的,因为Comeaus编译器的中间格式c代码无法获取,即使我们以某种方式获取了,也不能由普通的ANSI-C编译器进行编译。 - goldenmean
2
如果你的代码没有使用异常和模板,你可能有机会在旧版的cfront上运行你的代码。但正如MSalters所说,这将会很丑陋 :-) - lothar
它还必须不使用任何标准库功能。 - anon
如果C++可以完美地转换为C,那么这是否有效地消除了http://programmers.stackexchange.com/a/113316/24257的第1点和第2点?这是否意味着C不再具有任何比C++更客观的优势? - Pacerier
1
@Pacerier:它远非完美。它生成的C代码难以阅读和维护。但是没错,多年前C已经失去了与C++相比的任何优势。微软甚至不再费心使用C。 - MSalters
3
@MSalters,这个不可读并不重要,就像机器代码不可读并不重要一样。你用C++编程,然后当我们需要部署时,我们将C++转换为C进行部署。然后你继续编辑C++代码,我们重复这个过程。所以现在用C已经没有任何优势了,对吧? - Pacerier

24

http://llvm.org/docs/FAQ.html#translatecxx

它可以处理一些代码,但对于更复杂的实现可能会失败,因为它没有完全更新到一些现代C++惯例。因此,请尝试频繁编译您的代码,直到您了解允许使用什么。

版本9.0.1的命令行用法如下:

clang -c CPPtoC.cpp -o CPPtoC.bc -emit-llvm
clang -march=c  CPPtoC.bc -o CPPtoC.c

对于旧版本(过渡版本不确定),请使用以下语法:

llvm-g++ -c CPPtoC.cpp -o CPPtoC.bc -emit-llvm
llc -march=c  CPPtoC.bc -o CPPtoC.c
请注意,它创建的是GNU风格的C代码而不是真正的ANSI C代码。在您大量投入代码之前,请确保它对您有用。例如,某些嵌入式系统仅接受ANSI C代码。
此外请注意,生成的代码功能良好但相当难以阅读。我建议您注释并维护您的C++代码,不必担心最终的C代码。
编辑:虽然官方支持这种功能已被删除,但用户仍可以使用Julia语言开发人员提供的非官方支持(请参见此链接),以实现上述功能。

3
我尝试使用LLVM将hello_world.cpp转换为C文件,生成的C代码像机器码一样难看。预处理器的包含语句都消失了。 - MikimotoH
2
@MikimotoH,看起来是这样的,因为它不是一种语法到语法的源代码转换。它实际上是一个可以输出到C的编译器,这意味着您仍然依赖于任何链接的C++库。它最好用于调试或作为查看材料。顺便说一句:它可能很丑,但请相信它比机器码更好,而且您至少可以从中学习。您可以从clang c++到c中学到比任何反汇编更好的东西。 - J. M. Becker
4
如果有人需要将一些 C++ 代码编译到只有 C 编译器的奇怪机器/微控制器上,这仍然似乎是一个很好的解决方案。 - Cray
2
@Cray:我已经尝试过了,可悲的是LLVM的c后端不能转换为纯ANSI C标准代码,而是GNU C编译器代码。这排除了许多仅支持ANSI C编译器的芯片。 - tdihp
3
自v3.1版本起,C后端功能已被移除。"它存在许多问题,甚至无法编译任何非平凡程序。" - Wu Yongzheng
显示剩余2条评论

5
也许老牌的cfront可以做到?

5
据我所知,cfront 已经很长时间没有得到维护,而且不可能处理现代的 C++ 代码。 - Keith Thompson

5

虽然你可以在C语言中使用OO(例如通过将theType *this作为方法的第一个参数,并手动处理类似于多态的vtables),但是这从设计上来说永远不会特别令人满意,而且看起来也很丑陋(即使有一些预处理器的技巧)。

我建议至少考虑重新设计以比较这将如何运作。

总的来说,很多事情取决于一个关键问题的答案:如果你已经有了可以工作的C ++代码,为什么要使用C?


8
作者的理由显然是与具体情境相关的,但确实存在理由。有时候,在某个特定平台上并不存在 C++ 编译器,或者由于某些原因无法获取编译器。此外,它也是一种非常优秀的学习工具。 - J. M. Becker

4
编译器由两个主要模块组成:前端和后端。 编译器的前端分析源代码,并构建某种形式的“中间表示”,比源代码更容易被机器算法分析(例如,源代码C++旨在帮助人类程序员编写代码,而中间形式则旨在帮助简化分析该中间形式的算法)。 编译器的后端采用中间形式,然后将其转换为“目标语言”。 一般编译器的目标语言是各种处理器的汇编语言,但没有什么禁止编译器后端生成其他语言的代码,只要所述目标语言至少与常规CPU汇编语言一样灵活。 正如您可能想象的那样,C绝对像CPU的汇编语言一样灵活,因此从技术上讲,C++到C编译器确实不是问题。 因此,您有:C++ --- 前端 ---> 某些中间形式 --- 后端 ---> C 您可能希望查看这些人:http://www.edg.com/index.php?location=c_frontend(上面的链接仅用于说明可以做什么,他们以数万美元的价格授权其前端) 顺便说一下,据我所知,GNU没有C++到C编译器,这让我感到困惑。因为C语言相当小,其内部机制相当基础,编写一个C编译器需要约一年时间(我可以亲身告诉您这一点,因为我很多年前就写过这样的编译器,并且它会生成一个[虚拟]堆栈机中间代码),只需编写一次C编译器即可拥有维护、最新的C++编译器,这将是一件好事...

通用编译器的目标语言是各种处理器的汇编语言(或机器码?)。 - qPCR4vir
EDG不幸放弃了他们的C前端。 - VoteCoffee

2
这是一个旧帖子,但显然C++ Faq有一个部分(已归档的2013版本)。如果联系作者,这个部分显然会被更新,因此从长远来看这可能会更加最新,但这里是当前版本:
这取决于你的意思。如果你的意思是,将C++转换为易读且易维护的C代码是否可能?那么很抱歉,答案是否定的——C++的特性不能直接映射到C,而且生成的C代码不是人类可读的。如果你的意思是,是否有编译器将C++转换为C,以便在尚未拥有C++编译器的平台上进行编译?那么你很幸运——请继续阅读。
将C++编译为C的编译器对程序进行完整的语法和语义检查,并且刚好使用C代码作为生成目标代码的一种方式。这样的编译器不仅仅是一种高级宏处理器。(请不要给我发电子邮件,声称这些是预处理器——它们不是——它们是完整的编译器。)通过将所有ISO标准C++的特性转换为C来实现是可能的,除了异常处理之外,通常会产生与传统C++编译器生成的代码效率相当的目标代码。
以下是一些执行编译到C的产品:
- Comeau Computing提供基于Edison Design Group前端的编译器,输出C代码。 - LLVM是一个可下载的编译器,可以发出C代码。此外,请参见这里和这里。这里是通过LLVM进行C++到C转换的示例。 - Cfront,由Bjarne Stroustrup和AT&T的其他人完成的C++的原始实现,生成C代码。但是它有两个问题:自90年代中期开始经历了一系列的所有权变更后,获得许可证变得困难,并且开发也在同一时间停止了,因此它没有得到错误修复并且不支持任何较新的语言特性(例如异常、命名空间、RTTI、成员模板)。 - 与流行的神话相反,截至本文撰写时,还没有将C++转换为C的g++版本。这似乎是可以做到的事情,但我不知道是否有人已经做到了(尚未)。
请注意,您通常需要指定目标平台的CPU、操作系统和C编译器,以便生成的C代码将专门针对该平台。这意味着:(a)您可能无法将为平台X生成的C代码在平台Y上编译;(b)自己进行转换可能会很困难——使用其中一个工具可能会更便宜/更安全。
再次强调:不要给我发电子邮件说这些只是预处理器——它们不是——它们是编译器。

1
这并没有回答问题。 - AStopher
链接似乎已经损坏。 - Blastfurnace
2
Comeau Computing 现在似乎已经完全死亡。 - Kyle Huff

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接