这是一个很大的问题,所以让我先解决一些问题:
问题是:理论上是否可以将C ++或C99编译为作为原始源代码的便携式?
Cfront和Comeau C / C ++已经将C ++编译为C语言。但根据Comeau的销售人员的说法,对于Comeau来说,他们生产的C不是便携式的。我自己没有使用过Comeau编译器,但我推测其原因是:
#ifdef
等条件编辑已经解决。我的问题是这些问题是否可以以强有力的方式克服。换句话说,是否可以编写完美的 C ++到C编译器(以不可支持的C ++特性为模)?
诀窍在于你必须扩展宏以进行强大的解析,然后将它们折叠回未扩展的形式(因此它们再次是可移植的和与平台无关的)。但是,是否存在根本不可能的情况?
任何人都很难断然说“是的,这是可能的”,但我很有兴趣看到任何具体的反例:由于某些深层原因无法以这种方式编译的代码片段。我对C ++和C99反例感兴趣。
我将从一个粗略的例子开始,只是为了说明我认为反例的样子。
#ifdef __SSE__
#define OP <
#else
#define OP >
#endif
class Foo {
public:
bool operator <(const Foo& other) { return true; }
bool operator >(const Foo& other) { return false; }
};
bool f() { return Foo() OP Foo(); }
这很棘手,因为OP
的值以及此处生成的方法调用是特定于平台的。但似乎编译器可能会认识到语句的解析树依赖于宏的值,并将宏的可能性扩展为:
bool f() {
#if __SSE__
return Foo_operator_lessthan(...);
#else
return Foo_operator_greaterthan(...);
#endif
}
答案 0 :(得分:2)
这不仅在理论上是可行的,而且实际上也是微不足道的 - 使用cbe
目标的LLVM。
答案 1 :(得分:1)
理论上,所有图灵完备语言都是等价的。
您可以将C ++编译为目标代码,然后将其反编译为纯C或使用以纯C编写的解释器。
答案 2 :(得分:1)
理论上当然,任何事情都可以先编译成C语言,但这样做是不切实际的,特别是对C ++而言。
对于Foo运算符&lt;在您的示例中,它可以转换为:
bool isLess(const struct Foo * left, const struct Foo * right );
作为功能签名。 (如果C90不允许bool然后返回int或char,同样旧的C版本不允许使用const,只是不要使用它。)
虚函数更棘手,需要函数指针。
struct A
{
virtual int method( const std::string & str );
};
struct A
{
int (*method)( struct A*, const struct string *);
};
a.method( "Hello" );
a.method( &a, create_String( "hello" ) );
// and take care of the pointer returned by create_String
答案 3 :(得分:1)
存在许多细微差别。例如,请考虑以下行:
int i = UINT_MAX;
IIRC,在C ++中,它指定了一个实现定义的值。在C99和C89中,它分配实现定义的值,或者引发实现定义的信号。因此,如果你在C ++中看到这一行,你不能只是将它修改为未经修改的C89编译器,除非你做出不可移植的假设它不会发出信号。
不过,如果我记得错了,请考虑一下你自己与相对简单的表达方式相关的标准差异的例子......因此,正如“grep”所说,你可以这样做,因为C89是一种足够丰富的语言来表达一般计算。基于同样的原因,您可以编写一个发出Perl源代码的C ++编译器。
根据你的问题的声音,你想象编译器会对原始代码进行一组定义的修改,使其编译为C89。实际上,即使对于C ++或C99中的简单表达式,发出的C89也可能看起来与原始源不同。
另外,我忽略了可能是你无法实现的标准库的某些部分,因为C89不提供这些功能,所以你最终会得到一个“编译器”,但不是一个完整的实现。我不确定。正如dribeas指出的那样,低级函数(如VLA)存在问题 - 基本上你无法将C89“堆栈”作为C99“堆栈”使用。相反,您必须从C89动态分配内存以用于C99源中所需的自动变量。
答案 4 :(得分:1)
一个大问题是例外。可以使用setjmp
,longjmp
等来模拟它们,但与真正的设备感知展开引擎相比,这总是非常低效。
答案 5 :(得分:0)
http://www.comeaucomputing.com
没有比工作实例更好的可行性证明。 Comeau是最符合标准的c ++ 03编译器之一,它支持即将推出的标准的许多功能,但它并不真正生成二进制代码。它只是将您的c ++代码转换为可以使用不同的C后端编译的c代码。
至于便携性,我认为这是不可能的。如果没有特定于编译器的扩展,有些功能无法实现。我想到的第一个例子是C99动态数组:int n; int array[n];
无法在纯C89(AFAIK)中实现,但可以在alloca
等扩展程序之上实现。