![](/img/trans.png)
[英]Q&A: Where can i find the drafts of all C Standards (C89,C90,C99,C11,C18) and C++ Standards (C++98,C++03,C++11,C++17) as PDFs for free? [on hold]
[英]Could C++ or C99 theoretically be compiled to equally-portable C90?
这是一个很大的问题,所以让我先解决一些问题:
问题是:理论上可以将C ++或C99编译为C89,它与原始源代码一样可移植吗?
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
}
它不仅在理论上是可行的,而且实际上也是微不足道的 - 使用具有cbe
目标的LLVM。
从理论上讲,所有图灵完备语言都是等价的。
您可以将C ++编译为目标代码,然后将其反编译为plain C或使用以C语言编写的解释器。
理论上当然可以先将任何东西编译成C语言,但这样做是不切实际的,特别是对于C ++。
对于Foo运算符<在您的示例中,它可以转换为:
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
有许多微妙的差异。 例如,考虑以下行:
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源中所需的自动变量。
一个大问题是例外 。 可以使用setjmp
, longjmp
等来模拟它们,但与真正的设备感知的展开引擎相比,这总是非常低效。
http://www.comeaucomputing.com
没有比工作实例更好的可行性证明。 Comeau是最符合标准的c ++ 03编译器之一,它支持即将推出的标准的许多功能,但它并不真正生成二进制代码。 它只是将您的c ++代码转换为可以使用不同的C后端编译的c代码。
至于便携性,我认为这是不可能的。 如果没有特定于编译器的扩展,有些功能无法实现。 想到的第一个例子是C99动态数组: int n; int array[n];
int n; int array[n];
这不能在纯C89(AFAIK)中实现,但可以在alloca
之类的扩展上实现。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.