views:

504

answers:

9

I'm teaching a course in which students get their first experience programming in C. We're using gcc on Linux and (for beginning students) the user experience is terrible. I'm looking for a C front end that will do one or more of the following:

  1. If it cannot find a .h file, announce the fact and shut up. Don't spray screenfuls of garbage so that the information about the missing .h file is lost.

  2. If an known name appears in a type-like position, it should trigger a sane, sensible error message. For example, the source code

    typedef struct Queue {
        Array_T elements;
        int first, last, length;
    } Queue;
    

    Should trigger a message like

    Line 2: I saw `Array_T` used as a type, but it 
    has never been declared as a type.
    

    In this same situation, or especially in function prototypes, gcc produces incomprehensible gobbledegook.

  3. In an ideal world, the tool would also detect attempts to link libraries out of dependency order. After all, we know how to do topological sort now.

There is no requirement that the tool be able to compile any code. I am looking only for a way to get better error messages. The only hard constraint is that it has to be able to run on 64-bit Red Hat Enterprise Linux, because that's our teaching platform. Also, it has to understand C99.

I'm aware of research front ends like CIL and an older effort at AT&T, but I don't know how they are on error messages. Similar comments on the EDG front end, which is free for educational use. I'm also aware that Gimpel Software may have some commercial offerings that might fit the bill. I don't know what budget we have, but I'm willing to go to my department head and ask for money.

I ask the collective wisdom of StackOverflow: what C99 front ends are available which issue error messages that beginners can understand?

+21  A: 

clang has awesome error messages. For your example:

$ clang -c test.c
test.c:2:5: error: unknown type name 'Array_T'
    Array_T elements;
    ^
1 error generated.
$ gcc -c test.c
test.c:2: error: expected specifier-qualifier-list before ‘Array_T’
Carl Norum
I really wish we used `clang` instead of gcc for work. Those messages are far clearer.
birryree
Carl Norum
@kuropenguin clang is still way behind in the amount of stuff it can check. `gcc -std=c99 -pedantic -Wall -Wextra` + a set of warnings that are not included in this basic command and fit your workflow, is something I couldn't live without.
Let_Me_Be
+6  A: 

You should look at Clang: http://clang.llvm.org/features.html

One of its major benfits is much better error messages.

Burton Samograd
+7  A: 

Clang generates far better error messages. Get it and try compiling

#include <bogus.h>

It gives

aho.c:1:10: fatal error: 'bogus.h' file not found
#include <bogus.h>
         ^
1 error generated.

It even uses colors on ANSI terminals.

Try

typedef struct Queue {
    Array_T elements;
    int first, last, length;
} Queue;

which gives

aho.c:2:5: error: unknown type name 'Array_T'
    Array_T elements;
    ^
1 error generated.

These features are not just good for beginners. It's good for every programmer!

Yuji
A good programmer never has compile-time errors. :-) On the other hand, it would be great for compiling third-party software that's always full of bugs and non-portable assumptions that lead to compile-time errors.
R..
@R A good programmer never introduces a bug, but the (third-party) code he deals with is always written by the bad ones, yeah :)
mlvljr
@R Can you say that with template meta-programming in C++??
Yuji
+4  A: 

Have you considered a static code analysis tool? Lint will generally give sensible error messages and point out some potential errors the compiler would miss.

Nathon
+5  A: 

The EDG front end produces substantially better error messages than gcc as a rule. For your example, it (as delivered by Comeau) produces:

"c_err.c", line 2: error: identifier "Array_T" is undefined
      Array_T elements;
      ^

As far as a header that can't be found:

MODE:strict errors C99

"c_err.c", line 1: catastrophic error: could not open source file "foo.h"
  #include <foo.h>
                  ^

1 catastrophic error detected in the compilation of "c_err.c".
Compilation terminated.

For quality of error messages, EDG and clang are currently about equal, but I'd have to say that EDG still probably has better conformance than clang so not only are the error messages clear, but it's also more dependable about issuing them when (and only when) it should.

Jerry Coffin
+4  A: 

Try Eclipse for C/C++. While it uses gcc on the backend, it parses the output of gcc and correlates those errors back to your source code. Since it does use gcc, you set C99 by configuring how gcc is called with your source code. You would need to configure that for beginners probably...

Eclipse is free.

Compiling your example, I get many gcc errors if I look at them but Eclipse puts an red X near the source line and clearly indicates that lines has error: expected specifier-qualifier-list before 'Array_T' Not the friendliest error message, but it is better than seeing a bunch of errors scrolling by on the terminal...

You can also add different error parsers for Eclipse and probably can get just what your are looking for by adding a friendlier parser.

drewk
+1  A: 

Using gcc you may want to make linker error messages more informative using:

gcc -Wl,-Y,nnn

man 1 gcc | less -p '-Wl,option'
man 1 ld | less -p '-Y'

In addition, you may want to have a look at liberrhdl, http://www.public-software-group.org/errhdl.

frank
A: 

There's also: libslack(err) - message/error/debug/verbosity/alert messaging module

http://libslack.org/manpages/err.3.html

ceeit
But that won't make your compiler generate better error messages, only (possibly) your application.
DarkDust
A: 

Here's a handy macro by Chris Suter to create your own compile time checks.

/*

compile with:
gcc -Wall -O3 -o compile-time-check compile-time-check.c

./compile-time-check

Compile Time Checks
http://sutes.co.uk/2010/08/compile-time-checks.html

*/

#include <stdlib.h>
#include <stdio.h>


#define CHECK__(line, x) typedef char check_##line##_[(x) ? 1 : -1];
#define CHECK_(line, x) CHECK__(line, x)
#define CHECK(x) CHECK_(__LINE__, (x))

#pragma pack(push, 1)

struct x {
   uint8_t  a;
   uint32_t b;
};

#pragma pack(pop)

//CHECK (sizeof (struct x) == 4)
CHECK (sizeof (struct x) == 5)

int main(int argc, const char *argv[])
{
   printf("sizeof struct x:  %zu\n", sizeof (struct x));
   return 0;
}
jefd