Skip to the content of the web site.

Lesson 1.8: Compile-time errors

Previous lesson Next lesson


At this point, you may have made an error in entering your code so that the compiler does not actually run, but rather it indicates an error during compilation. In repl.it or your IDE, these messages will appear in a window or panel. If you are using command-line compilation, you will see the error messages immediately after you call the compiler.

Warnings versus errors

While compilers will halt if the code cannot be compiled, compilers may also try to help you with warnings. In general, any warning will allow the compilation process to continue, but you should consider reading the warning, as it may give a hint that all is not well in the state of Denmark, or your code, for that matter. This topic will, however, focus on errors.

Errors

We will describe two types of errors that you may cause your code to not compile. We will refer to these as compile-time errors, although in future courses you will be able to differentiate these into syntax errors and static semantic errors. If you are interested in the difference between these two, please consider reading this article.

To examine various errors, we will modify the following code:

 1  #include 
 2
 3  // Function declarations
 4  int main();
 5  double my_sin( double x );
 6  
 7  // Function definitions
 8  int main() {
 9      std::cout << "Hello world!" << std::endl;
10      std::cout << "sin(0.5) = " << my_sin(0.5) << "!" << std::endl;
11  
12      return 0;
13  }
14  
15  double my_sin( double x ) {
16      // This uses a Taylor series approximation of sin(x)
17      return ((-0.00019841269841269841*x*x
18              + 0.0083333333333333333)*x*x
19              - 0.16666666666666667)*x*x + 1.0;
20  }

You can look at this code at repl.it. Warning: The error messages generated below are from the GNU g++ compiler. If you try these in a different IDE (XCode or VisualStudio) or in repl.it (which uses the clang++ compiler), you will get different error messages, but that should not take away from this lesson. You will also find that some compilers are more helpful than others.

We will look at different classes of errors.

#include statements

We will start by looking at all the different ways that you could incorrectly type an include statement, and in each case, the error message will be different. We will look at

  1. include <iostream>
  2. #inculde <iostream>
  3. #include iostream>
  4. #include <iostreem>
  5. #include <iostream

1. include <iostream>

In the first case, we forgot the pound symbol (or hash symbol):

example.cpp:1:1: error: 'include' does not name a type
 include <iostream>
 ^
example.cpp: In function 'int main()':
example.cpp:7:5: error: 'cout' is not a member of 'std'
     std::cout << "Hello world!" << std::endl;
     ^
example.cpp:7:36: error: 'endl' is not a member of 'std'
     std::cout << "Hello world!" << std::endl;
                                    ^
example.cpp:8:5: error: 'cout' is not a member of 'std'
     std::cout << "sin(0.5) = " << my_sin(0.5) << "!" << std::endl;
     ^
example.cpp:8:57: error: 'endl' is not a member of 'std'
     std::cout << "sin(0.5) = " << my_sin(0.5) << "!" << std::endl;
                                                         ^

There are a lot of error messages here, but what is critical is that you should always look at the first. The compiler finds an error, but then tries to continue compiling the source code to possibly find other errors. In this case, however, fixing the first error solves all remaining problems.

Here, the message is error: 'include' does not name a type. Because there is no pound symbol, the compiler attempts to interpret include like a user-defined type. Up to now, we have seen int and double, but later in this course, we will see that you can easily define a type with the identifier include (although, we wouldn't recommend it).

2. #inculde <iostream>

In this case, we misspelled include, so the error message is

example.cpp:1:2: error: invalid preprocessing directive #inculde
 #inculde <iostream>
  ^
example.cpp: In function 'int main()':
example.cpp:7:5: error: 'cout' is not a member of 'std'
     std::cout << "Hello world!" << std::endl;
     ^
example.cpp:7:36: error: 'endl' is not a member of 'std'
     std::cout << "Hello world!" << std::endl;
                                    ^
example.cpp:8:5: error: 'cout' is not a member of 'std'
     std::cout << "sin(0.5) = " << my_sin(0.5) << "!" << std::endl;
     ^
example.cpp:8:57: error: 'endl' is not a member of 'std'
     std::cout << "sin(0.5) = " << my_sin(0.5) << "!" << std::endl;
                                                         ^

Again, the first error message immediately identifies the error: invalid preprocessing directive #inculde. There are only a small number of preprocessing directives, and inculde isn't one of them.

3. #include iostream>

Here, we forget the opening angled bracket in the include directive:

example.cpp:1:11: error: #include expects "FILENAME" or 
 #include  iostream>
           ^
                             ...ignore all other errors...

The first error message is clear, there are only two formats allowed for include statements:

#include <FILENAME>
#include "FILENAME"

4. #include <iostraem>

Next, the compiler will try to access the file. Of course, if the file name is spelled wrong, it won't be found (or worse, the wrong one may be found...):

example.cpp:1:20: fatal error: iostraem: No such file or directory
 #include <iostraem>
                    ^

Now, this is a new error: a fatal one, meaning that the compiler cannot continue from this point on: the missing file is fatal to the compilation process.

5. #include <iostream

Forgetting the closing angled bracket leads to a simple and straight-forward error message:

example.cpp:1:19: error: missing terminating > character
 #include <iostream
                   ^

Misspelling types

As before, when we forgot to put a pound symbol in front of include and the compiler tried to interpret include as a type, it is often possible to misspell types. There are certain times when the compiler, if it sees an identifier, it immediately assumes it is a type, such as int or double. Suppose, however, you misspelled int as integer, thinking that they are the same:

integer main();

The error message is very clear:

example.cpp:4:1: error: 'integer' does not name a type
 integer main();
 ^

Case sensitivity

In C++, the identifiers main and Main are different, but some programming languages use Main instead of main. If you have previously used such a programming language (such as C#), you may be inclined to make a mistake here:

int Main();

int Main() {
    // ... and so on...
    return 0;
}

Now the error message is:

/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crt1.o: In function '_start':
(.text+0x20): undefined reference to 'main'
collect2: error: ld returned 1 exit status

While Main() is a perfectly good identifier for a function, when a compiler is trying to convert source code into an executing program, it is looking for a main() function, and if it doesn't find it, it will indicate that when trying to call main(), it did not find such a function defined anywhere.

Missing a semicolon

If you have two statements and you forget a semicolon after the first, the compiler will simply continue looking forward and try to understand how the next statement combines with the first. For example, if you forget a semicolon after the function declaration:

double my_sin( double x )

int main() {
	return 0;
}

the compiler simply sees:

double my_sin( double x ) int main() {
	return 0;
}

This does not make any sense within the context of the C++ programming language. The compiler tries to be helpful:

example.cpp:8:1: error: expected initializer before 'int'
 int main() {
 ^

The hint here is the word before, and so while the error message does not indicate there is a missing semicolon, if you read that message it suggests you look back and you may find the missing semicolon.

Definition: missing semicolons
If an error message points to a line where you cannot understand why there is an error at that location, start looking back. It is likely you forgot a semicolon or perhaps a delimiter.

Forgetting namespaces

While we have not gotten into the details of namespaces, some of you may be familiar with code such as:

#include <iostream>
using namespace std;
int main() {
  cout << "Hello World!\n";
}

You can compile this program at repl.it.

While this compiles, it uses programming practices that would be considered unacceptable in most professional environments. One consequence, however, is that students often forget to include std:: before cout or endl. Fortunately, the compiler does try to help:

example.cpp: In function ‘int main()’:
example.cpp:9:5: error: ‘cout’ was not declared in this scope
     cout << "Hello world!" << endl;
     ^~~~
example.cpp:9:5: note: suggested alternative:
In file included from example.cpp:1:0:
/usr/include/c++/7/iostream:61:18: note:   ‘std::cout’
   extern ostream cout;  /// Linked to standard output
                  ^~~~
example.cpp:9:31: error: ‘endl’ was not declared in this scope
     cout << "Hello world!" << endl;
                               ^~~~
example.cpp:9:31: note: suggested alternative:
In file included from /usr/include/c++/7/iostream:39:0,
                 from example.cpp:1:
/usr/include/c++/7/ostream:590:5: note:   ‘std::endl’
     endl(basic_ostream<_CharT, _Traits>& __os)
     ^~~~

In both cases, it suggests using std::cout and std::endl.

Forgetting quotes

When using literal strings, you may forget to include either the opening or closing double quote. In the first case, the compiler then attempts to continue interpreting what you meant to be a string of characters as part of the C++ program, while in the second it continues to treat everything up to the end of the line as part of the string.

example.cpp:9:30: warning: missing terminating " character [enabled by default]
     std::cout << Hello world!" << std::endl;
                              ^
example.cpp:9:5: error: missing terminating " character
     std::cout << Hello world!" << std::endl;
     ^
example.cpp: In function 'int main()':
example.cpp:9:18: error: 'Hello' was not declared in this scope
     std::cout << Hello world!" << std::endl;
                  ^
example.cpp:9:24: error: expected ';' before 'world'
     std::cout << Hello world!" << std::endl;
                        ^

Here, the first error message is that there is an opening double quote on the line, but no closing double quote. Next, it sees Hello as an identifier, but that identifier has not previously been defined (say, as a function name). Finally, the compiler sees two identifiers juxtaposed (Hello world) and cannot make sense of this, so it suggests there should have been a semicolon after the Hello. This suggestion is wrong for what we intended this program to do, but it is not an invalid suggestion.

If you forget the closing double quote, the error is clear:

example.cpp:9:18: warning: missing terminating " character [enabled by default]
     std::cout << "Hello world! << std::endl;
                  ^
example.cpp:9:5: error: missing terminating " character
     std::cout << "Hello world! << std::endl;
     ^

Misspelled identifiers

In C++, it is often easy to misspell an identifier. If, for example, in the above program, you declared the function to be my_sin, but then when you called it, you instead used the identifier mysin, the compiler is quick to point out the problem:

example.cpp: In function 'int main()':
example.cpp:10:44: error: 'mysin' was not declared in this scope
std::cout << "sin(0.5) = " << mysin(0.5) << "!" << std::endl;
                                       ^

Invalid comments

One of the biggest mistakes first-year students do is use a single slash when they intend add a comment. If your editor uses color highlighting, it should be easier to see that this is an issue. One common mistake for students to make is to leave all commenting to the end: "It compiles and runs correctly, so I'm done! Now to add the damned comments..." After adding the comments, the student will will forget to try recompiling. Now, the comment is treated as if it was a division operator. For example, if you replace the last // with a / in the above code, you get an error message like:

example.cpp: In function 'double my_sin(double)':
example.cpp:16:5: error: expected primary-expression before '/' token
     / This uses a Taylor series approximation of sin(x)
     ^
example.cpp:16:7: error: 'This' was not declared in this scope
     / This uses a Taylor series approximation of sin(x)
       ^
example.cpp:16:12: error: expected ';' before 'uses'
     / This uses a Taylor series approximation of sin(x)
            ^

First, it says that it is requiring an expression before the division sign, which is true, as the division operator requires two operands. Next, the compiler indicates that it does not recognize the identifier This. Finally, it is also confused by two identifiers (This uses) juxtaposed, as this is invalid C++ syntax.

Forgetting operators

In this example, it may be easy for a programmer to have xx or x x instead of x*x. In the first case, xx is an identifier different from x, and so the compiler will simply state that it does not recognize xx; while in the second, it will complain that you have two identifiers juxtaposed without an operator between them.

Unmatched delimiters

Suppose you forgot either an opening or closing parenthesis. For example, if you remove one of the two ((, you have

    return (-0.00019841269841269841*x*x
            + 0.0083333333333333333)*x*x
            - 0.16666666666666667)*x*x + 1.0;

The error message is now:

example.cpp: In function 'double my_sin(double)':
example.cpp:19:34: error: expected ';' before ')' token
             - 0.16666666666666667)*x*x + 1.0;
                                  ^
example.cpp:19:34: error: expected primary-expression before ')' token
example.cpp:19:34: error: expected ';' before ')' token

The compiler is pointing at the second closing parenthesis and saying. Instead, it suggests that there should have been a semicolon before the closing parenthesis, as

    return (-0.00019841269841269841*x*x
            + 0.0083333333333333333)*x*x
            - 0.16666666666666667; // *x*x + 1.0;

would be a valid return statement. In this case, the suggestion is wrong, but it's hinting as to the problem.

Next, let us remove one of the closing parentheses:

    return ((-0.00019841269841269841*x*x
            + 0.0083333333333333333*x*x
            - 0.16666666666666667)*x*x + 1.0;

Now, the error is correct, but the suggestion is in the wrong place:

example.cpp: In function 'double my_sin(double)':
example.cpp:19:45: error: expected ')' before ';' token
             - 0.16666666666666667)*x*x + 1.0;
                                             ^

It is suggesting the following:

    return ((-0.00019841269841269841*x*x
            + 0.0083333333333333333*x*x
            - 0.16666666666666667)*x*x + 1.0);

so while that is wrong location, it is still a not-unreasonable suggestion.

Suppose you forget a closing brace for a function body. The compiler will recommend that you add one, so if you remove the closing brace of the my_sin function body, the error message is:

example.cpp: In function 'double my_sin(double)':
example.cpp:19:45: error: expected '}' at end of input
             - 0.16666666666666667)*x*x + 1.0;
                                             ^

In this particular case, the suggestion is correct: adding a closing brace after the semicolon produces a program that compiles and in this case produces the correct executable.

Two binary operators in a row

Similarly, it is illegal to have two binary operators in a row. Suppose we remove the string in the first statement and add an extra division sign in the second:

    std::cout << << std::endl;

In this case, the error message indicates that the compiler is expecting something before the second operator (for example, a string:

In function 'int main()':
6:18: error: expected primary-expression before '<<' token

Suppose we try to compare a string and the std::endl identifier. This may happen if we accidentally type < instead of <<:

Invalid operands

Suppose you use the wrong operator, and then you have operands that make no sense for that operator. While we have not covered the < (less-than) operator, it should make sense that we cannot compare the "magnitude" of std::cout with std::endl:

	std::cout << "Hello world!" < std::endl;

Recall that std::cout << "Hello world!" is an operator that returns a reference to std::cout. The error message goes on for a long time:

 In function 'int main()':
9:33: error: no match for 'operator<' (operand types are 'std::basic_ostream<char>' and '<unresolved overloaded function type>')
9:33: note: candidates are:
In file included from /usr/include/c++/4.9/string:52:0,
                 from /usr/include/c++/4.9/bits/locale_classes.h:40,
                 from /usr/include/c++/4.9/bits/ios_base.h:41,
                 from /usr/include/c++/4.9/ios:42,
                 from /usr/include/c++/4.9/ostream:38,
                 from /usr/include/c++/4.9/iostream:39,
                 from 1:
/usr/include/c++/4.9/bits/basic_string.h:2612:5: note: template<class _CharT, class _Traits, class _Alloc> bool std::operator<(const _CharT*, const std::basic_string<_CharT, _Traits, _Alloc>&)
     operator<(const _CharT* __lhs,
     ^

/usr/include/c++/4.9/bits/basic_string.h:2612:5: note: template argument deduction/substitution failed:
6:40: note: mismatched types 'const _CharT*' and 'std::basic_ostream<char>'
In file included from /usr/include/c++/4.9/string:52:0,
                 from /usr/include/c++/4.9/bits/locale_classes.h:40,
                 from /usr/include/c++/4.9/bits/ios_base.h:41,
                 from /usr/include/c++/4.9/ios:42,
                 from /usr/include/c++/4.9/ostream:38,
                 from /usr/include/c++/4.9/iostream:39,
                 from 1:
/usr/include/c++/4.9/bits/basic_string.h:2600:5: note: template<class _CharT, class _Traits, class _Alloc> bool std::operator<(const std::basic_string<_CharT, _Traits, _Alloc>&, const _CharT*)
     operator<(const basic_string<_CharT, _Traits, _Alloc>& __lhs,
     ^
/usr/include/c++/4.9/bits/basic_string.h:2600:5: note: template argument deduction/substitution failed:
6:40: note: 'std::basic_ostream<char>' is not derived from 'const std::basic_string<_CharT, _Traits, _Alloc>'
In file included from /usr/include/c++/4.9/string:52:0,
                 from /usr/include/c++/4.9/bits/locale_classes.h:40,
                 from /usr/include/c++/4.9/bits/ios_base.h:41,
                 from /usr/include/c++/4.9/ios:42,
                 from /usr/include/c++/4.9/ostream:38,
                 from /usr/include/c++/4.9/iostream:39,
                 from 1:
/usr/include/c++/4.9/bits/basic_string.h:2588:5: note: template<class _CharT, class _Traits, class _Alloc> bool std::operator<(const std::basic_string<_CharT, _Traits, _Alloc>&, const std::basic_string<_CharT, _Traits, _Alloc>&)
     operator<(const basic_string<_CharT, _Traits, _Alloc>& __lhs,
     ^
/usr/include/c++/4.9/bits/basic_string.h:2588:5: note: template argument deduction/substitution failed:
6:40: note: 'std::basic_ostream<char>' is not derived from 'const std::basic_string<_CharT, _Traits, _Alloc>'
In file included from /usr/include/c++/4.9/bits/stl_algobase.h:67:0,
                 from /usr/include/c++/4.9/bits/char_traits.h:39,
                 from /usr/include/c++/4.9/ios:40,
                 from /usr/include/c++/4.9/ostream:38,
                 from /usr/include/c++/4.9/iostream:39,
                 from 1:
 + almost 100 more lines of error messages...

From the verbosity of this error message, you may think that you suddenly committed a cardinal sin; however, what the compiler is doing is trying to tell you why it is confused and when you have a better understanding of C++, you know it is trying to help you by giving suggestions. The most important line for you, however, is the first:

 In function 'int main()':
9:33: error: no match for 'operator<' ...
This says that on line 9 at column 33, the compiler does not know what to do with the < operator.

Operators and misspelled identifiers

Suppose you were to incorrectly spell std::endl and replace it with std::end. The error message is less clear, but reading the first two lines:

 In function 'int main()':
9:33: error: no match for 'operator<<' (operand types are 'std::basic_ostream<char>' and '<unresolved overloaded function type>')
 + almost 100 more lines of error messages...

What this error message says is that it does not understand how it is supposed to have a << operator work with something it doesn't comprehend. It actually describes the std::end as an unresolved overloaded function type. While the error message is not entirely useful, it does point you to approximately where the error is.

If it tells you what is wrong, why not fix it?

In at least two examples above (with the missing semicolon and the missing closing brace) the error message told you exactly what was wrong and how to fix it. You may ask, why does the compiler simply not make the corrections and then carry on? The problem is, what it thinks is the right correction to make may not be what you actually meant!

Important suggestion:
As you go forward and learn new aspects of the C++ programming language, it may not be that bad an idea to occasionally make deliberate mistakes so that you can see what the error messages are.

Review

In your own words, describe each of these concepts:

Questions and practice:

1. What error do you get if you misspell return?

2. What happens if you misspell the function name main, say with min?

3. If you misspelled include, you get a cascade of subsequent errors. If there are multiple errors, always try to fix the first error first; this may eliminate subsequent errors.

4. If you write int main(] { instead of using a closing parenthesis, what are the errors? How is the error worded?

Solutions.


Previous lesson Next lesson