Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ #include semantics

This is a multiple question for the same pre-processing instruction.

1 - <> or "" ?

Apart from the info found in the MSDN:

#include Directive (C-C++)

1.a: What are the differences between the two notations?
1.b: Do all compilers implement them the same way?
1.c: When would you use the <>, and when would you use the "" (i.e. what are the criteria you would use to use one or the other for a header include)?

2 - #include {TheProject/TheHeader.hpp} or {TheHeader.hpp} ?

I've seen at least two ways of writing includes of one's project headers. Considering that you have at least 4 types of headers, that is:

  • private headers of your project?
  • headers of your project, but which are exporting symbols (and thus, "public")
  • headers of another project your module links with
  • headers of a compiler or standard library

For each kind of headers:

2.a: Would you use <> or "" ?
2.b: Would you include with {TheProject/TheHeader.hpp}, or with {TheHeader.hpp} only?

3 - Bonus

3.a: Do you work on project with sources and/or headers within a tree-like organisation (i.e., directories inside directories, as opposed to "every file in one directory") and what are the pros/cons?

like image 208
paercebal Avatar asked Oct 07 '08 16:10

paercebal


People also ask

What C is used for?

C programming language is a machine-independent programming language that is mainly used to create many types of applications and operating systems such as Windows, and other complicated programs such as the Oracle database, Git, Python interpreter, and games and is considered a programming foundation in the process of ...

What is C in C language?

What is C? C is a general-purpose programming language created by Dennis Ritchie at the Bell Laboratories in 1972. It is a very popular language, despite being old. C is strongly associated with UNIX, as it was developed to write the UNIX operating system.

Is C language easy?

Compared to other languages—like Java, PHP, or C#—C is a relatively simple language to learn for anyone just starting to learn computer programming because of its limited number of keywords.

What is C full form?

Full form of C is “COMPILE”. One thing which was missing in C language was further added to C++ that is 'the concept of CLASSES'.


1 Answers

After reading all answers, as well as compiler documentation, I decided I would follow the following standard.

For all files, be them project headers or external headers, always use the pattern:

#include <namespace/header.hpp> 

The namespace being at least one directory deep, to avoid collision.

Of course, this means that the project directory where the project headers are should be added as "default include header" to the makefile, too.

The reason for this choice is that I found the following information:

1. The include "" pattern is compiler-dependent

I'll give the answers below

1.a The Standard

Source:

  • C++14 Working Draft n3797 : https://isocpp.org/files/papers/N3797.pdf
  • C++11, C++98, C99, C89 (the section quoted is unchanged in all those standards)

In the section 16.2 Source file inclusion, we can read that:

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.

This means that #include <...> will search a file in an implementation defined manner.

Then, the next paragraph:

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.

This means that #include "..." will search a file in an implementation defined manner and then, if the file is not found, will do another search as if it had been an #include <...>

The conclusion is that we have to read the compilers documentation.

Note that, for some reason, nowhere in the standards the difference is made between "system" or "library" headers or other headers. The only difference seem that #include <...> seems to target headers, while #include "..." seems to target source (at least, in the english wording).

1.b Visual C++:

Source:

  • http://msdn.microsoft.com/en-us/library/36k2cdd4.aspx

#include "MyFile.hpp"

The preprocessor searches for include files in the following order:

  1. In the same directory as the file that contains the #include statement.
  2. In the directories of any previously opened include files in the reverse order in which they were opened. The search starts from the directory of the include file that was opened last and continues through the directory of the include file that was opened first.
  3. Along the path specified by each /I compiler option.
  4. (*) Along the paths specified by the INCLUDE environment variable or the development environment default includes.

#include <MyFile.hpp>

The preprocessor searches for include files in the following order:

  1. Along the path specified by each /I compiler option.
  2. (*) Along the paths specified by the INCLUDE environment variable or the development environment default includes.

Note about the last step

The document is not clear about the "Along the paths specified by the INCLUDE environment variable" part for both <...> and "..." includes. The following quote makes it stick with the standard:

For include files that are specified as #include "path-spec", directory searching begins with the directory of the parent file and then proceeds through the directories of any grandparent files. That is, searching begins relative to the directory that contains the source file that contains the #include directive that's being processed. If there is no grandparent file and the file has not been found, the search continues as if the file name were enclosed in angle brackets.

The last step (marked by an asterisk) is thus an interpretation from reading the whole document.

1.c g++

Source:

  • https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
  • https://gcc.gnu.org/onlinedocs/cpp/Include-Syntax.html
  • https://gcc.gnu.org/onlinedocs/cpp/Include-Operation.html
  • https://gcc.gnu.org/onlinedocs/cpp/Invocation.html
  • https://gcc.gnu.org/onlinedocs/cpp/Search-Path.html
  • https://gcc.gnu.org/onlinedocs/cpp/Once-Only-Headers.html
  • https://gcc.gnu.org/onlinedocs/cpp/Wrapper-Headers.html
  • https://gcc.gnu.org/onlinedocs/cpp/System-Headers.html

The following quote summarizes the process:

GCC [...] will look for headers requested with #include <file> in [system directories] [...] All the directories named by -I are searched, in left-to-right order, before the default directories

GCC looks for headers requested with #include "file" first in the directory containing the current file, then in the directories as specified by -iquote options, then in the same places it would have looked for a header requested with angle brackets.

#include "MyFile.hpp"

This variant is used for header files of your own program. The preprocessor searches for include files in the following order:

  1. In the same directory as the file that contains the #include statement.
  2. Along the path specified by each -iquote compiler option.
  3. As for the #include <MyFile.hpp>

#include <MyFile.hpp>

This variant is used for system header files. The preprocessor searches for include files in the following order:

  1. Along the path specified by each -I compiler option.
  2. Inside the system directories.

1.d Oracle/Sun Studio CC

Source:

  • http://docs.oracle.com/cd/E19205-01/819-5265/bjadq/index.html

Note that the text contradict itself somewhat (see the example to understand). The key phrase is: "The difference is that the current directory is searched only for header files whose names you have enclosed in quotation marks."

#include "MyFile.hpp"

This variant is used for header files of your own program. The preprocessor searches for include files in the following order:

  1. The current directory (that is, the directory containing the “including” file)
  2. The directories named with -I options, if any
  3. The system directory (e.g. the /usr/include directory)

#include <MyFile.hpp>

This variant is used for system header files. The preprocessor searches for include files in the following order:

  1. The directories named with -I options, if any
  2. The system directory (e.g. the /usr/include directory)

1.e XL C/C++ Compiler Reference - IBM/AIX

Source:

  • http://www.bluefern.canterbury.ac.nz/ucsc%20userdocs/forucscwebsite/c/aix/compiler.pdf
  • http://www-01.ibm.com/support/docview.wss?uid=swg27024204&aid=1

Both documents are titled "XL C/C++ Compiler Reference" The first document is older (8.0), but is easier to understand. The second is newer (12.1), but is a bit more difficult to decrypt.

#include "MyFile.hpp"

This variant is used for header files of your own program. The preprocessor searches for include files in the following order:

  1. The current directory (that is, the directory containing the “including” file)
  2. The directories named with -I options, if any
  3. The system directory (e.g. the /usr/vac[cpp]/include or /usr/include directories)

#include <MyFile.hpp>

This variant is used for system header files. The preprocessor searches for include files in the following order:

  1. The directories named with -I options, if any
  2. The system directory (e.g. the /usr/vac[cpp]/include or /usr/include directory)

1.e Conclusion

The pattern "" could lead to subtle compilation error across compilers, and as I currently work both on Windows Visual C++, Linux g++, Oracle/Solaris CC and AIX XL, this is not acceptable.

Anyway, the advantage of "" described features are far from interesting anyway, so...

2. Use the {namespace}/header.hpp pattern

I saw at work (i.e. this is not theory, this is real-life, painful professional experience) two headers with the same name, one in the local project directory, and the other in the global include.

As we were using the "" pattern, and that file was included both in local headers and global headers, there was no way to understand what was really going on, when strange errors appeared.

Using the directory in the include would have saved us time because the user would have had to either write:

#include <MyLocalProject/Header.hpp> 

or

#include <GlobalInclude/Header.hpp> 

You'll note that while

#include "Header.hpp" 

would have compiled successfully, thus, still hiding the problem, whereas

#include <Header.hpp> 

would not have compiled in normal circonstances.

Thus, sticking to the <> notation would have made mandatory for the developer the prefixing of the include with the right directory, another reason to prefer <> to "".

3. Conclusion

Using both the <> notation and namespaced notation together removes from the pre-compiler the possibility to guess for files, instead searching only the default include directories.

Of course, the standard libraries are still included as usual, that is:

#include <cstdlib> #include <vector> 
like image 97
paercebal Avatar answered Oct 05 '22 20:10

paercebal