Can C ++ or C99 theoretically be compiled into an equally portable C90?

This is a big question, so let me clean up a few things:

  • We will not ignore the fact that some C ++ functions cannot be implemented in C (for example, support for preliminary basic initialization for any global static object that is linked in).
  • This is a thought experiment about what is theoretically possible. Please do not write to say how strong it will be (I know), or what I should do X instead. This is not a practical question, this is a fun theoretical one. :)

The question arises: is it theoretically possible to compile C ++ or C99 on C89, which is as portable as the source code?

Cfront and Comeau C / C ++ will already compile C ++ for C. But for the Comeau C they manufacture are not portable, according to Comeau sales staff. I myself have not used the Comeau compiler, but I assume that the reasons for this are:

  • Macros, such as INT_MAX, offsetof (), etc., have already been extended, and their expansion is platform dependent.
  • Conditional compilation, such as #ifdef , is already allowed.

My question is whether these issues can be overcome in a durable way. In other words, can an excellent C ++ to C compiler be written (modulo unsupported C ++ functions)?

The trick is that you need to expand the macros to do a strong parsing, but then collapse them back into their unexpanded forms (so they are again portable and platform independent). But are there any cases when this is fundamentally impossible?

It would be very difficult to categorically say “yes, it’s possible”, but I’m very interested to see some specific counterexamples: code fragments that cannot be compiled in this way for some serious reason. I'm interested in counterexamples C ++ and C99.

I will start with a rough example to emphasize what, in my opinion, a counterexample may look like.

 #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(); } 

This is difficult because the value of OP and therefore the method call that is generated here is platform dependent. But it looks like the compiler could recognize that the operator syntax tree is dependent on the value of the macro and extends the capabilities of the macro like something like:

 bool f() { #if __SSE__ return Foo_operator_lessthan(...); #else return Foo_operator_greaterthan(...); #endif } 
+4
source share
6 answers

It is not only theoretically possible, but also practically trivial to use LLVM with the goal of cbe .

+2
source

Theoretically, all language languages ​​with Turing are equivalent.

You can compile C ++ for object code and then decompile it into simple C or use an interpreter written in simple C.

+1
source

In theory, of course, everything could be compiled in C at first, but this is impractical, especially for C ++.

For the Foo <operator in your example, it can be converted to:

 bool isLess(const struct Foo * left, const struct Foo * right ); 

as a function signature. (If C90 does not allow bool, then they return int or char, and similar old versions of C that do not allow const simply do not use it).

Virtual functions are more complex, you need function pointers.

 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
source

There are several subtle differences. For example, consider the line:

 int i = UINT_MAX; 

IIRC, in C ++ this assigns a value defined for implementation. In C99 and C89, it assigns a value defined by an implementation, or raises a signal defined by an implementation. Therefore, if you see this line in C ++, you cannot simply pass it to the C89 compiler without changes unless you make the intolerable assumption that it will not pick up the signal.

Btw, if I remember incorrectly, think about your own example of differences in standards regarding relatively simple expressions ...

So, as grep says, you can do this because C89 is a rich enough language to express general computations. For the same reason, you can write a C ++ compiler that emits a Perl source.

From the sound of your question, however, you imagine that the compiler will make a number of specific changes to the source code to compile it as C89. In fact, even for simple expressions in C ++ or C99, the emitted by C89 may not look like the original source at all.

In addition, I ignored that there may be some parts of the standard libraries that you simply cannot implement, because C89 does not offer features, so you will get a “compiler”, but not a full implementation. I'm not sure. And, as dribeas points out, low-level functions like VLA pose problems - basically you can't use the C89 stack "as your C99 stack" portable. Instead, you will have to dynamically allocate memory from C89 to use for the automatic variables needed in the C99 source.

+1
source

One big problem is exceptions . Perhaps they can be emulated using setjmp , longjmp , etc., but it will always be extremely inefficient compared to the real engine to unlock the device.

+1
source

http://www.comeaucomputing.com

There is no better proof of possibility than a working example. Como is one of the most suitable C ++ 03 compilers and supports many functions of the upcoming standard, but in fact it does not generate binary code. It just translates your C ++ code into c-code, which can be compiled using other C files.

As for portability, I would suggest that this is not possible. There are some functions that cannot be implemented without special extensions for the compiler. The first example that comes to mind is C99 dynamic arrays: int n; int array[n]; int n; int array[n]; which cannot be implemented in pure C89 (AFAIK), but can be implemented on top of alloca extensions.

0
source

Source: https://habr.com/ru/post/1344240/


All Articles