Могут ли C ++ или C99 теоретически быть скомпилированы в одинаково переносимый C90? - PullRequest
4 голосов
/ 18 марта 2011

Это большой вопрос, поэтому позвольте мне кое-что из этого сделать:

  1. Давайте проигнорируем тот факт, что некоторые функции C ++ не могут быть реализованы в C (например, поддержкаосновная инициализация для любого глобального статического объекта, который связан с).
  2. Это мысленный эксперимент о том, что теоретически возможно.Пожалуйста, не пишите, чтобы сказать, насколько сложно это будет (я знаю), или что я должен вместо этого делать X.Это не практический вопрос, это забавный теоретический вопрос.:)

Вопрос заключается в следующем: возможно ли теоретически скомпилировать C ++ или C99 в C89, который такой же переносимый , что и исходный код?

Cfront иComeau C / C ++ уже компилировать C ++ в C.Но для Comeau C, который они производят, не является портативным, по словам торгового персонала Comeau.Я сам не использовал компилятор Comeau, но я предполагаю, что причины этого:

  1. Макросы, такие как INT_MAX, offsetof () и т. Д., Уже расширены, и их расширение является платформенным.конкретный.
  2. Условная компиляция, такая как #ifdef, уже решена.

Мой вопрос заключается в том, можно ли решить эти проблемы надежным способом.Другими словами, может ли быть написан совершенный C ++ to 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
}

Ответы [ 6 ]

2 голосов
/ 18 марта 2011

Это не только теоретически возможно, но и практически тривиально - используйте LLVM с целью cbe.

1 голос
/ 18 марта 2011

Одна большая проблема - исключения . Может быть возможно эмулировать их, используя setjmp, longjmp и т. Д., Но это всегда будет крайне неэффективно по сравнению с реальным механизмом раскрутки с учетом реальных устройств.

1 голос
/ 18 марта 2011

Есть ряд тонких отличий.Например, рассмотрим строку:

int i = UINT_MAX;

IIRC, в C ++ это присваивает значение, определяемое реализацией.В C99 и C89 он присваивает значение, определяемое реализацией, или выдает сигнал, определяемый реализацией.Так что, если вы видите эту строку в C ++, вы не можете просто передать ее компилятору C89 без изменений, если не сделаете непереносимое предположение, что он не вызовет сигнал.

Кстати, если я 'Вы помните неправильно, подумайте о своем собственном примере различий в стандартах, касающихся относительно простых выражений ...

Итак, как говорит "grep", вы можете сделать это, потому что C89 - достаточно богатый язык для выражения общихвычисление.По тем же причинам вы могли бы написать компилятор C ++, который генерирует исходный код Perl.

Однако, исходя из вашего вопроса, вы представляете, что компилятор сделает ряд определенных модификаций исходного кода, чтобы он компилировался как C89.На самом деле, даже для простых выражений в C ++ или C99 испускаемый C89 может совсем не выглядеть как исходный.

Кроме того, я проигнорировал, что может быть некоторымчасти стандартных библиотек, которые вы просто не можете реализовать, потому что C89 не предлагает таких возможностей, поэтому вы получите «компилятор», а не полную реализацию.Я не уверен.И, как указывает Дрибес, низкоуровневые функции, такие как VLA, представляют проблемы - в основном вы не можете использовать «стек» C89 в качестве своего «стека» C99.Вместо этого вам придется динамически выделять память из C89, чтобы использовать ее для автоматических переменных, необходимых в источнике C99.

1 голос
/ 18 марта 2011

В теории, конечно, сначала все может быть скомпилировано в C, но это непрактично, особенно для C ++.

Для оператора Foo <в вашем примере его можно преобразовать в: </p>

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
1 голос
/ 18 марта 2011

Теоретически все языки, полные по Тьюрингу, эквивалентны.

Вы можете скомпилировать C ++ в объектный код, а затем декомпилировать его в простой C или использовать интерпретатор, написанный в простом C.

0 голосов
/ 18 марта 2011

http://www.comeaucomputing.com

Нет лучшего доказательства осуществимости, чем рабочий пример. Comeau - один из наиболее подходящих компиляторов c ++ 03, он поддерживает многие функции будущего стандарта, но на самом деле он не генерирует двоичный код. Он просто переводит ваш код на C ++ в код на C, который может быть скомпилирован с различными бэкэндами C.

Что касается переносимости, я бы предположил, что это невозможно. Есть некоторые функции, которые не могут быть реализованы без специальных расширений компилятора. Первый пример, который приходит на ум, это динамические массивы C99: int n; int array[n];, которые не могут быть реализованы в чистом C89 (AFAIK), но могут быть реализованы поверх расширений, таких как alloca.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...