tags:

views:

1512

answers:

9

Is there any materials about how to use #include crorrectly? I didn't find any c/c++ text book that explain this usage in details. In formal project, I always get confused in dealing with it. Thanks for your help.

+12  A: 

The big one that always tripped me up was this:

This searches in the header path:

#include <stdio.h>

This searches in your local directory:

#include "myfile.h"

Second thing you should do with EVERY header is this:

myfilename.h:

#ifndef MYFILENAME_H
#define MYFILENAME_H
//put code here
#endif

This pattern means that you cannot fall over on redefining the headers in your compilation (Cheers to orsogufo for pointing out to me this is called an "include guard"). Do some reading on how the C compiler actually compiles the files (before linking) because that will make the world of #define and #include make a whole lot of sense to you, the C compiler when it comes to parsing text isn't very intelligent. (The C compiler itself however is another matter)

Spence
The pattern is called "include guard".
Paolo Tedesco
And most compilers allow the `#pragma once` equivalent
xtofl
@xtofi: No they don't. That is a MS extension. Very few other compilers support it.
Martin York
@Spence: No that is not correct. The second include also searches a set of directories (just a different set)
Martin York
@Martin: Indeed - it's only MS and gcc support #pragma once (and the latter doesn't officially). It seems especially hard to define the concept of 'the same file' in a rigorous way. Why don't we have an equivalent to the php "include" vs "require"?
xtofl
@xtofl: I agree it would be nice feature. But even the php stuff fails for the same reason: http://us2.php.net/require
Martin York
the _H and uppercase are kinda important too. Once when I had less experience I used the include guard with the same name and case as the class definition in the file.. it kinda drove me batty for a while that it wouldn't compile.
Dan
Martin is right. the difference between "" and <> is not certain. it's implementation defined what that difference is. most compilers, however, will make look into the file-relative path first when "" is used.
Johannes Schaub - litb
+9  A: 
  • Check Large-Scale C++ Software Design from John Lakos if you have the money.
  • Google C++ coding guidelines also have some OK stuff.
  • Check Sutter Herb materials online (blog) as well.

Basically you need to understand where include headers are NOT required, eg. forward declaration. Also try to make sure that include files compiles one by one, and only put #includes in h files when it's a must (eg. templates).

+1 for mentioning forward declarations.
Luc Touraille
I think what you talked about is what I need.Stuff above are easy enough so that everyone knows it.
MainID
+2  A: 

Header files are C's way of separating interface and implementation. They are divided into two types: standard and user-defined header files. A standard header file, such as string.h, allows us access to the functionality of an underlying C library. You should #include it in every .c file which uses the relevant functionality. Usually this uses brackets as in #include A user-defined header file exposes your implementation of functions to other programmers or other parts of your C code. If you have implemented a module called rational.c for calculations with rational numbers, it should have a corresponding rational.h file for its public interface. Every file which uses the functionality should #include rational.h, and also rational.c should #include it. Usually this is done using #include "rational.h" The part of compilation which does the #includes is called the C preprocessor. It mostly does text substitutions and pastes text. Spence is correct in his pattern for preventing duplicate #includes, which mess up the namespace. This is the base of inclusion, GNU Make gives you lots more power, and lots more trouble as well.

Yuval F
A: 

You use #include "yourfile.h" if yourfile.h is in the curent working directory and #include if the path to yourfile.h file was included in the c++ include Directories (somewere in configuration, example: c:\mylib\yourfile.h , the path c:\mylib\ has to be specified as an include directory) Also you can include .cpp and .hpp (h plus plus). There a particular set of files that can be writen like: #include . For this to particular example work you need to specify using namespace std;

There is a very nice software that is integrated with microsoft's visual c++ , and shows the include paths. http://www.profactor.co.uk/includemanager.php

+1  A: 

In addition to the other comments, remember that you don't need to #include a header in another header if you only have a pointer or reference. E.g.:

Header required:

#include "Y.h"
class X
{
   Y y; // need header for Y
};

Header not required:

class Y; 
class X
{
   Y* y; // don't need header for Y
};
//#include "Y.h" in .cpp file

The second example compiles faster and has less dependencies. This can be important in large code bases.

Andy Brice
Thanks,is it the so-called forward declaration?
MainID
Yup, that's a forward declaration. Very useful for speeding up compilation. It only works when the compiler doesn't need details; you can't use it for base classes, actual members, that sort of thing.
David Thornley
A: 

check out the discussion on using #include<filename.h> #include<filename> for c++ includes of c libraries

yesraaj
A: 

Edit: Andy Brice also made this point in a briefer way.

Folling up in null's answer, the most important thing to think about is where you put your #include's.

When you write a #include the preprocessor literally includes the contents of the file you list in the current file, including any #includes in those files as well. This can obviously lead to very large files at compile time (coad bloat) so you need to consider carefully if an #include is needed.

In a standard code file layout where you have a .h file for a class with the class and function declarations, and then a .cpp implementation file, you should be be careful of the number of #includes that go in the header file. This is because, every time you make a change to the header file, any files that also include it (ie. that use your class) will also have to be recompiled; if the header itself has lots of includes then every file that uses the class gets bloated significantly at compile time.

It is better to use forward declarations where possible, so that you can write the method signatures etc. and then #include the relevant files in the .cpp file so that you can actually use the classes and structures that your code depends on.

//in myclass.h
class UtilClass; //forward declaration of UtilClass - avoids having to #include untilclass.h here

class MyClass
{
    MyClass();
    ~MyClass();

    void DoSomethingWithUtils(UtilClass *util); //this willcompile due toforward declaration above
};

//then in the .cpp
#include utilclass.h

void MyClass::DoSomethingWithUtils(UtilClass *util)
{
    util->DoSomething(); //this will compile because the class definition is included locally in this .cpp file
}
xan
+4  A: 

So your compiler may support 2 unique search paths for include files:
Informally we could call the system include path and the user include path.
The #include <XX> searches the system include path.
The #include "XX" searches the user include path then the system include path.

Checking the draft standard n2521:
Section 16.2:

2 A preprocessing directive of the form 

  # include < h-char-sequence> new-line 

  searches a sequence of implementation-defined places for a header identified
  uniquely by the specified sequence between the < and > delimiters, and
  causes the replacement of that directive by the entire contents of the
  header. How the places are specified or the header identified is
  implementation-defined. 

3 A preprocessing directive of the form 

  # include " q-char-sequence" new-line 

  causes the replacement of that directive by the entire contents of the
  source file identified by the specified sequence between the " " delimiters.
  The named source file is searched for in an implementation-defined manner.
  If this search is not supported, or if the search fails, the directive is
  reprocessed as if it read

  # include < h-char-sequence> new-line 

  with the identical contained sequence (including > characters, if any)
  from the original directive.

An example of this would by gcc

  -isystem <dir>              Add <dir> to the start of the system include path
  -idirafter <dir>            Add <dir> to the end of the system include path
  -iwithprefix <dir>          Add <dir> to the end of the system include path
  -iquote <dir>               Add <dir> to the end of the quote include path
  -iwithprefixbefore <dir>    Add <dir> to the end of the main include path
  -I <dir>                    Add <dir> to the end of the main include path

To see where your gcc is searching do this:

g++ -v -E -xc++ /dev/null -I LOOK_IN_HERE
#include "..." search starts here:
#include <...> search starts here:
  LOOK_IN_HERE
  /usr/include/c++/4.0.0
  /usr/include/c++/4.0.0/i686-apple-darwin9
  /usr/include/c++/4.0.0/backward
  /usr/local/include
  /usr/lib/gcc/i686-apple-darwin9/4.0.1/include
  /usr/include
  /System/Library/Frameworks (framework directory)
  /Library/Frameworks (framework directory)
End of search list.

So how do you use this knowledge.
There are several school of thought. But I always list my libraries from most specific to most general.

Example

File: plop.cpp

#include "plop.h"
#include "plop-used-class.h"

/// C Header Files
#include <stdio.h>    // I know bad example but I drew a blank

/// C++ Header files
#include <vector>
#include <memory>

This way if the header file "plop-used-class.h" should have included <vector> this will be cought by the compiler. If I had put the <vector> at the top this error would have been hidden from the compiler.

Martin York
A: 

Just an addendum to Andy Brice's answer, you can also make do with forward declarations for function return values:

class Question;
class Answer;

class UniversityChallenge
{
...
    Answer AskQuestion( Question* );
...
};

Here's a link to a question I asked a while back with some good answers http://bytes.com/groups/c/606466-forward-declaration-allowed.

Steve Folly