tl;dr: We added explicit problem types for C++ functions and programs, and from now on CloudCoder will compile C submissions using a C compiler rather than a C++ compiler. Previous problems that required C++ features will break, but can be fixed trivially by changing them to the appropriate C++ problem type.
Everyone knows that C++ is a better C than C, right?
Kernighan and Ritchie famously used Stroustrup’s C++ compiler to compile all of the example programs in The C Programming Language, 2nd ed, since many features of ANSI/ISO C appeared first in C++. C++ compilers perform stricter checking than C compilers, so when we started working on CloudCoder we used g++ (the GNU C++ compiler) to compile submissions for the
C_PROGRAM problem types. Our thought at the time was that stricter checking would benefit students by alerting them to potential bugs at compile time.
What we didn’t consider at the time is that C has been evolving independently of C++ for a long time, and modern C has a number of features that are incompatible with C++. If these features were relegated to obscure corners of the language, this wouldn’t necessarily be a problem. Unfortunately, we recently found one feature of C that is (1) extremely useful for writing CloudCoder exercises, and (2) illegal in C++.
It’s all about the structs
Struct types are the C mechanism for creating new data types. Writing functions that take pointers to instances of struct types is the basis for data abstraction in C, and is an essential technique for writing C programs of any complexity. We have found that many students find this style of programming challenging, and allowing them to use CloudCoder to practice writing functions that operate on struct instances via pointers can help them achieve proficiency.
For example, let’s consider a struct type to represent a point in the x/y coordinate plane:
We might want to ask students to write a function to compute the distance between two points:
For CloudCoder problems that test functions, the input to each test case is a list of literal arguments to pass to the tested function. To test the
computeDistance function above, we need to pass pointers to literal instances of
struct Point. And that’s where our problem arises. A possible input might be something like:
When CloudCoder creates a test driver program, it will paste these arguments into a function call:
and then check that the value returned by the function matches the expected output value. Here is the problem: in C++, literal struct values are temporary values, and it is not legal to take the address of a temporary. So, the test program generated by CloudCoder will not be a legal C++ program. You can’t write function-based exercises where the function takes pointers to structs if the resulting code will be compiled by a C++ compiler. (Interestingly, it would be perfectly fine to have the function take const references to the struct type in C++, since a temporary can be passed by const reference.)
In C, there is no problem: struct literals are lvalues, and it is perfectly fine to take their address. So, to write exercises based on functions similar to the one described above, we need CloudCoder to compile the code with a C compiler, not a C++ compiler.
Fixing the problem, but also breaking stuff
To fix the problem, we did something we should have done a while ago: created
CPLUSPLUS_PROGRAM problem types. Submissions for these problem types are compiled with a C++ compiler. The existing
C_PROGRAM will now use a C compiler (gcc) to compile submissions.
Unfortunately, this will cause any
C_PROGRAM exercise or submission that used C++ features to fail. There are quite a few such exercises in the CloudCoder exercise repository. The good news is that there is a trivial fix: change the problem type to
CPLUSPLUS_PROGRAM. Presto, the exercise will continue to work as before.
This feature has been pushed to the version control repository and will be included in the next release.