繁体   English   中英

C ++或C99理论上可以编译成同等便携的C90吗?

[英]Could C++ or C99 theoretically be compiled to equally-portable C90?

这是一个很大的问题,所以让我先解决一些问题:

  1. 让我们忽略一些事实,即某些C ++特性无法在C中实现(例如,支持链接到的任何全局静态对象的预主要初始化)。
  2. 这是一个关于理论上可行的思想实验。 请不要写这么说(我知道)有多难,或者我应该做X。 这不是一个实际的问题,它是一个有趣的理论问题。 :)

问题是:理论上可以将C ++或C99编译为C89,它与原始源代码一样可移植吗?

Cfront和Comeau C / C ++已经将C ++编译为C语言。 但根据Comeau的销售人员的说法,对于Comeau来说,他们生产的C不是便携式的。 我自己没有使用过Comeau编译器,但我推测其原因是:

  1. 诸如INT_MAX,offsetof()等宏已经被扩展,并且它们的扩展是特定于平台的。
  2. #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源中所需的自动变量。

一个大问题是例外 可以使用setjmplongjmp等来模拟它们,但与真正的设备感知的展开引擎相比,这总是非常低效。

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM