Different errors in C code on different compilers

Asked

Viewed 194 times

0

In the following code below there is an error that the Lccx86 compiler for Windows claims to exist, but I copied the codes from a C class I am watching.

Class link, for those interested

In the C Online compiler https://www.tutorialspoint.com/compile_c_online.php It displays other errors!

  1. What’s the mistake?
  2. Why, different compilers display different errors?
  3. The language is not standardized?
  4. Or I’m not understanding the mistakes?

#define MAX 50;

typedef int TIPOCHAVE;

typedef struct {
    TIPOCHAVE chave;
} REGISTRO;

typedef struct {
    REGISTRO A[MAX]; //Linha 10
    int nroElem;
} LISTA;

some of the mistakes:

PS D:\Cursos\C> lcc .\arranjos.c
Error arranjos.c: 10  syntax error; found `;' expecting ']'
Error arranjos.c: 10  syntax error; found `]' expecting '}'
Error arranjos.c: 10  skipping `]'
Error arranjos.c: 10  empty declaration

2 answers

5

What’s the mistake?

Has a ; in the #define, and should not have, this is wrong syntax. If the class taught like this, run away from it. In any compiler this does not do what you want.

Why different compilers display different errors?

Because they are different. They can handle the code as long as they obey the specification.

The language is not standardized?

Yes, and as long as the compiler respects what has been specified it can function as it wishes. If the specification told every detail to be followed it would not need to have more than one compiler. Each one does as he thinks best and each programmer chooses the compiler that best suits him.

The compiler can even add new things.

There are compilers that don’t even meet the specification. They say they compile C, but they don’t say they meet the standard. No one is required to meet the standard, just can’t say that answers without answering. Even so do not know if something would happen if you lie.

Or I’m not understanding the mistakes?

That only you can answer.

The mistake

Behold What is undefined behavior, unspecified and defined by the implementation?.

But that’s not even the case. The compiler can handle the errors however you want, you can check in the order you want, you can stop anytime you want.

As we do not have the errors in the two compilers we cannot compare the behaviors.

It is a fact that an error can trigger others and solving this, solves all, so much so that there is only one and showed 4, possibly show others if the code was larger or if the compiler did not stop when it already screwed up a lot.

And the error in one location generated error in another. First understand like the #define works and the alternatives to it, what I would have used in this case. I consider it almost obsolete.

So when the code is compiled, there is a processing of the text exchanging all the texts MAX for 50; which is the text that is written in your code. Let’s see the first occurrence of it:

REGISTRO A[MAX];

Once processed it would be

REGISTRO A[50;];

That one ; within the declaration of array is prohibited in any compiler.

There are compilers who "understand" the type of error and can give a better message, this is his prerogative to do, the language does not say how the error should be treated, what the message should be, none of that. Then some compiler may give a message indicating the error at the right place, that is on line 1, since the compiler may understand that this is a common error. But most will prefer to give the error where it actually occurred.

Smarter compilers are harder to develop, and often take longer to compile to find the real mistake. In general only compilers who have a lot of effort is smart, so I only recommend using "exotic" compilers if it’s really necessary.

And then one error triggers the others since the compiler understands that after 50 is closing the line. So the syntax on that line is wrong because it wasn’t closed, and the next line of code is wrong because no new line starts with a ], and he gets lost thinking that would come the closure of the structure and still end up leaving a ; loose that is enclosing nothing, since there was an earlier closure where it should not.

That is why I say and I repeat: the person does not know how to program until he understands all the characters that are in his code, until the blank space. Everything has an influence on code, be it pro compiler or readability.

This code compiles:

#define MAX 50

typedef int TIPOCHAVE;

typedef struct {
    TIPOCHAVE chave;
} REGISTRO;

typedef struct {
    REGISTRO A[MAX]; //Linha 10
    int nroElem;
} LISTA;

int main(void) {
    // your code goes here
    return 0;
}

Behold working in the ideone. And in the repl it.. Also put on the Github for future reference.

  • 1

    It’s not that it’s "forbidden" to put the ; at the end of #define; is that, if the ; is in the definition, that ; will be replaced in the occurrences of token defined. This is rarely what one wants; but it may be that the programmer has taken this into account. In any case, the Preprocessor does not prohibit the use of ; at the end of #define, and obediently replaces the token with the ;.

  • @Wtrmute this, I was not happy in the words, I will edit

  • stdio include that. h was unnecessary? since we don’t have a print?

  • @Dorathoto actually stayed in the ideone feedback, I didn’t even need it. I improved the answer.

3


Preprocessing

The problem is this semicolon:

#define MAX 50;

The reason is that the #define works (speaking in a somewhat simplistic way) when copying and pasting in the rest of the code the occurrences of the first word for the remainder. They are solved in a step called pre-processing, which aims to solve all #defines and #includes and also delete comments. Preprocessing occurs on top of the source code when making text replacements. The actual build starts on top of the already pre-processed source code. Even, you can see the output of the preprocessor by invoking your compiler with the correct flags. In the case of LCC this is so:

lcc -E arranjos.c

GCC is the same way:

gcc -E arranjos.c

This command will preprocess the file arranjos.c.

In the case of your program, the preprocessor will replace MAX for 50;, producing this:

typedef int TIPOCHAVE;

typedef struct {
    TIPOCHAVE chave;
} REGISTRO;

typedef struct {
    REGISTRO A[50;];
    int nroElem;
} LISTA;

And it’s this code above that the real compiler will see. Note line 10:

    REGISTRO A[50;];

Note that this semicolon within the array dimension causes the compiler to choke.

Finally, different compilers will give different errors because the language specification tells how the compiler should interpret well-formed code and how to turn it into an executable. However, when what happens is malformed code, the specification speaks little. Thus, what the compiler should do against the malformed code ends up being in charge of those who developed the compiler, and in this way, different compilers will give different errors.

Mistakes

  1. In case, the first mistake you have is quite clear:

    syntax error; found `;' expecting ']'

    This error says that the compiler found a semicolon that shouldn’t be there and expected a bracket.

    The subsequent errors occur because the compiler ended up getting confused with the first error, but I suppose his error recovery strategy was to pretend that what he wanted to find, but didn’t find, was actually there. So, upon finding the ; when he was expecting a ], he pretended that this:

    typedef struct {
        REGISTRO A[50;];
        int nroElem;
    } LISTA;
    

    was actually that:

    typedef struct {
        REGISTRO A[50];];
        int nroElem;
    } LISTA;
    

    Meaning he faked/kicked/guessed that you had forgotten to put the ].

  2. But then he finds another ] the more. At this point, he hoped or the definition of another field of struct or the } of the end of struct. The second option is the simplest, so he launched as error this:

    Error arranjos.c: 10 syntax error; found `]' expecting '}'

    And then to recover, he pretended that the } was there:

    typedef struct {
        REGISTRO A[50];}];
        int nroElem;
    } LISTA;
    
  3. At this stage, the compiler finds again the ] there silly, without being closing anything. The solution is to jump it by emitting error Error arranjos.c: 10 skipping `]' and pretend the code was like this:

    typedef struct {
        REGISTRO A[50];};
        int nroElem;
    } LISTA;
    
  4. With these modifications, he ends up seeing the typedef in this way:

    typedef struct {
        REGISTRO A[50];};
    

    And in this case, the name that comes before this last ;. So he makes one more mistake:

    Error arranjos.c: 10 empty declaration

  5. After that, the compiler should produce other errors. In particular, it will think that nroElem is out of the struct and will see the } Then there’s no more.

In fact, you only had one mistake, which was the ; within the #define. However, due to improper compiler error recovery strategy, he ended up seeing a lot of different errors where he had only one because he got confused. Each compiler has a different error strategy than the others (I stress again that the C language specification focuses on well-formed code and speaks little about how to deal with malformed code).

On the other hand, you can’t blame the compiler because there is no optimal error recovery strategy. When the code is malformed, the compiler loses the structural guarantees that the language would give it and he has to guess what the programmer wanted, and in many cases this process of guessing can lead to very bad results. For example, try compiling a code in Python, Java or any other language with the C compiler to see that any compiler will get quite confused and that whenever he tries to make an effort to understand something, he will end up getting even more confused.

Finally, GCC should use a better error recovery strategy in this case (in other cases it may be different). Here’s the GCC output with this code:

arranjos.c:1:15: error: expected ‘]’ before ‘;’ token
 #define MAX 50;
           ^
arranjos.c:10:16: note: in expansion of macro ‘MAX’
 REGISTRO A[MAX]; //Linha 10
            ^~~

In particular, GCC is intelligent (at least in this case) to know that the error occurred within a macro (i.e., a #define) and give more accurate error messages than the LCC without getting confused.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.