16

This is one of my most dreaded C/C++ compiler errors:

file.cpp(3124) : fatal error C1004: unexpected end-of-file found

file.cpp includes almost a hundred header files, which in turn include other header files. It's over 3000 lines. The code should be modularized and structured, the source files smaller. We should refactor it. As a programmer there's always a wish list for improving things.

But right now, the code is a mess and the deadline is around the corner. Somewhere among all these lines—quite possibly in one of the included header files, not in the source file itself—there's apparently an unmatched brace, unmatched #ifdef or similar. The problem is that when something is missing, the compiler can't really tell me where it is missing. It just knows that when it reached end of the file it wasn't in the right parser state.

Can you offer some tools or other hints / methodologies to help me find the cause for the error?

flodin
  • 5,215
  • 4
  • 26
  • 39

13 Answers13

10

If the #includes are all in one place in the source file, you could try putting a stray closing brace in between the #includes. If you get an 'unmatched closing brace' error when you compile, you know it all balances up to that point. It's a slow method, but it might help you pinpoint the problem.

njplumridge
  • 336
  • 3
  • 11
  • 4
    A binary search is your friend here. And you can do the same thing with #endif, not to mention spanning the rest of the source file. Its not fixed when the error stops, of course ;-) – RBerteig May 08 '09 at 20:27
8

One approach: if you have Notepad++, open all of the files (no problem opening 100 files), search for { and } (Search -> Find -> Find in All Open Documents), note the difference in count (should be 1). Randomly close 10 files and see if the difference in count is still 1, if so continue, else the problem is in one of those files. Repeat.

JRL
  • 76,767
  • 18
  • 98
  • 146
  • this will not work if there is at least one string which contain `}` or `{` – noisy Oct 28 '11 at 11:32
  • This idea helped me, thanks. I have 756 open parentheses and 755 close parentheses in this file : – Rag Jan 03 '13 at 08:29
  • 2
    Later: found it ten lines from the BOTTOM after searching for every single open parenthesis in the file and visually confirming its partner... – Rag Jan 03 '13 at 08:43
4

Handy tip:

For each header file, auto-generate a source file which includes it, then optionally contains an empty main method, and does nothing else. Compile all of these files as test cases, although there's no point running them.

Provided that each header includes its own dependencies (which is a big "provided"), this should give you a better idea which header is causing the problem.

This tip is adapted from Google's published C++ style guide, which says that each component's source files should include the interface header for that component before any other header. This has the same effect, of ensuring that there is at least one source file which will fail to compile, and implicate that header, if there's anything wrong with it.

Of course it won't catch unmatched braces in macros, so if you use much in the way of macros, you may have to resort to running the preprocessor over your source file, and examining the result by hand and IDE.

Another handy tip, which is too late now:

Check in more often (on a private branch to keep unfinished code out of everyone else's way). That way, when things get nasty you can diff against the last thing that compiled, and focus on the changed lines.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
  • Regarding the second tip: for us I think the problem is more often that people don't build the whole product before checking in. If the problem is in a header file, it probably worked for whoever checked it in, in the components he was building. But in another context, with other #defines, in a different project, the same file suddenly starts causing problems. – flodin May 08 '09 at 12:48
  • Still, if that other developer had checked in a bunch of intermediate versions, then at the forensics stage you could pull each of them in turn, compile it in the configuration which is now failing, and perhaps narrow down the point which caused the problem. Not guaranteed, though, since they may have taken the approach of "get my config working first, then jigger it to make the rest work". In which case their intermediate versions will fail for reasons unrelated to the reason their final version fails. – Steve Jessop May 08 '09 at 13:03
2

Very late to the party, but on linux you can use fgrep -o

  -o, --only-matching
          Print only the matched (non-empty) parts of a matching line,
          with each such part on a separate output line.

So if you fgrep -o { then you'll get a list of all the opening braces in your file.

You can then pipe that to wc -l and that will give you the number of opening braces in your file.

With a bit of bash arithmetic, you can do the same with closing braces, and then print the difference.

In the below example I'm using git status -s to get the short-format output of all modified files from my git repo, and then I'm iterating over them to find which files may have mismatched braces

for i in $(git status -s | awk '{print $2}'); do 
    open=$(fgrep -o { $i | wc -l);   # count number of opening braces
    close=$(fgrep -o } $i | wc -l);  # count number of closing braces 
    diff=$((open-close));            # find difference
    echo "$diff : $i";               # print difference for filename
done
Steve Lorimer
  • 27,059
  • 17
  • 118
  • 213
2

Hints:

  • make small changes and recompile after each small change
  • for unmatched braces, use an editor/IDE that supports brace match hilighting
  • if all else failds, Ye Olde method of commenting out blocks of code using a binary chop approach works for me
1

This might not be relevant to your problem, but I was getting an "Unexpected #else" error when framing some header files in an #if/#else/#endif block.

I found that if I set the problem modules to not use pre-compiled headers, the problem went away. Something to do with the "#pragma hdrstop" should not be within an #if/#endif.

Pierre
  • 4,114
  • 2
  • 34
  • 39
1

I think using some editor with brace highlighting will help. There should also be some tools around that do automatic indention on code.

EDIT: Does this vim script help? It seems to do #ifdef highlighting.

schnaader
  • 49,103
  • 10
  • 104
  • 136
  • Yes, but that only helps me with the source file proper. The nasty part is that the source file is including almost a hundred header files, and one of those headers is likely where the problem exists. – flodin May 08 '09 at 12:06
  • See my edit, #ifdef highlighting could help with the header files – schnaader May 08 '09 at 12:16
  • That vim script looks really useful, thanks! Still it won't help me if the problem exists in one of the header files. – flodin May 08 '09 at 12:16
  • Why wouldn't it? You can edit the header files, can't you, so the highlighting works for them, too. If editing all the header files is too much work, you can comment the "#include" statements until the code compiles and find the header files that causes the problem this way. – schnaader May 08 '09 at 12:25
  • That is certainly a way of doing it. I wouldn't say it is too much work, but I would love it if there was a more efficient way. Keep in mind that those 100 include files in turn include other files, and the problem could be several levels deep. The total number of included files could easily be in the thousands, so it's a lot of trial and error. Add do that a lot of #ifdefs that contain nested #ifdefs and #defines; just tracking down what is defined and what isn't takes a lot of effort, but is necessary to follow preprocessor's parsing path. – flodin May 08 '09 at 12:39
1

Can you create a script that actually does all the including, and then write the whole stuff to a temporary file? Or try the compiler for helping you with that? Then you can use the bracket highlighting features of various editors to find the problem and you'll probably be able to identify the file. (An extra help can be to have your script add a comment around every included file).

andreas buykx
  • 12,608
  • 10
  • 62
  • 76
0

I recently ran into this situation while refactoring some code and I'm not a fan of any of the answers above. The problem is that they neglect to incorporate a pretty basic assumption:

Any given file (most likely) will have matching braces and if/endif macros.


While it is true one can have a C++ source file that opens a bracket or an if block and includes another module that closes it, I have never seen this in practice. Something like the following:

foo.cpp

namespace Blah{
#include "bar.h"

bar.h:

}; /// namespace Blah

So with the assumption that any given file / module contains matching sets of braces and preprocessor directives, this problem is now trivial to solve. We just need a script to read the files / count the brackets & directives that it finds and report mismatches.

I've implemented one in Ruby here, feel free to take and adapt to your needs:

https://gist.github.com/movitto/6c6d187f7a350c2d71480834892552ab

Mo Morsi
  • 111
  • 1
  • 3
0

I just spent an hour with a problem like this. It was very hard to spot, but in the end, I had typed a double # on one line:

##ifdef FEATURE_X ...

That broke the world.

Easy one to search for though.

radsdau
  • 495
  • 5
  • 16
0

The simplest and fastest solution is to comment file from the end by consistent blocks. If the error still exists, then you not yet comment the open brace.

Andry
  • 2,273
  • 29
  • 28
0

Have a look at this question (Highlighting unmatched brackets in vim)

Community
  • 1
  • 1
kgiannakakis
  • 103,016
  • 27
  • 158
  • 194
0

Pre-compile your code first, this will create a big chunk with the include files stuffed into the same file. Then you can use those brace-matching scripts.

Makis
  • 12,468
  • 10
  • 62
  • 71
  • This works if the problem is an unmatched brace. But if it's an unmatched #ifdef, the preprocessor will refuse to run. – flodin May 08 '09 at 12:34
  • Well, after that you at least know which it is. If it's the preprocessor directives, you could then do something like (copy all files to the same directory first) grep -n -P \#ifdef\|#else\|#elif\|#endif * > precomp.txt And unless the amount of these constructs is huge, you should be able to go through that file. A couple of hundred of lines in that file wouldn't take too long to check. – Makis May 08 '09 at 12:55