About headers in C++

Asked

Viewed 1,619 times

2

Some doubts have arisen specifically about the creation of headers:

  1. If I create a test file. h, and another test.cpp, as the C++ compiler does to relate the test.cpp file to the test file. h, that is, what are the criteria used? What prevents the test settings. h in test.cpp from being replaced by others?
  2. (Complement to the previous question) if we create a test file. h and implement it in a different filename, say, proof.cpp, yet the program compiles. How to explain this?
  3. Why does the following code not compile? I get a Undefined error'.
/* teste.h */
#ifndef TESTE
#define TESTE

inline double cubo(double a);

#endif // TESTE
/* Teste.cpp: implementação de Teste.h.*/
#include "teste.h"

double cubo(double a)
{
    return a * a * a;
}
/* Principal.cpp */
#include <iostream>
#include "teste.h"

int main()
{
    std::cout << cubo(2.0) << std::endl;
}
  1. When implementing a function inline in an archive .cpp, makes any difference removing the qualifier inline the definition of the function, leaving only in the declaration?
  2. I read in several places that define functions inline in header files helps prevent "multiple function definitions". It could explain how these "multiple definitions can occur"?

I am using Qt Creator on Linux (Kubuntu 16.04). The compiler is gcc (g++).

2 answers

2

Below are still the specific questions, but now understand that the questions actually is about the error generated by inline.

Whenever you use the inline the code of implementation the function needs to be on the same build unit, it cannot be elsewhere. It is not enough to have only the job signature. This is a little different. Since the function code will probably have to be used in your new code and will not be called, the source should be available right there. So in this case the correct is to have the header like this:

#ifndef TESTE
#define TESTE

double cubo(double a) {
    return a * a * a;
}

#endif // TESTE

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

Documentation on the inline.

If I create a test file. h, and another test.cpp, as the C++ compiler does to relate the test.cpp file to the test file. h, that is, what are the criteria used? What prevents the test settings. h in test.cpp from being replaced by others?

Nothing, who does this is code, the compiler only does what is determined by the code.

(Complement to the previous question) if we create a test file. h and implement it in a different filename, say, proof.cpp, yet the program compiles. How to explain this?

Exactly for what is above, there are no implicit links, the code says what it should link, so it works with names you want. Of course the content needs to be adequate.

Why does the following code not compile? I get a Undefined error'.

This is the error of linkediting, it found all the code, but did not find the binary needed to create the executable. It depends on how you are compiling, it may just be that you did not add the .cpp, may need to indicate where the previously compiled code is. This may be a problem in the IDE project configuration.

When implementing an inline function in a file. cpp, it makes some difference to remove the inline qualifier from the function definition, leaving only in the declaration?

Generally speaking it makes no difference because the compiler will do the inline if he wants to. But for the purpose of having the code can make a difference.

If you say you are inline there has to be an executable code from that function, and you probably didn’t. When you don’t use it it may be that it’s solved elsewhere.

I read in various places that defining inline functions in header files helps prevent "multiple function definitions". Could explain how these "multiple definitions can occur"?

The question is a little wide, but roughly the header is a centralizer, there is the correct place to place the functions inline since they will be used where you need them. If you start spreading them over various files who ensures that they are all the same?

  • The example code I gave compiles if I remove the qualifier inline. It was my fault for not explaining this before.

  • @Muriloneto now understood his real doubt, edited the answer and gave a solution to the problem.

  • I get it. The documentation you indicated also helped me understand how multiple definitions occur. The documentation states that "functions included in multiple source files must be inline". After reading and re-reading I realized that what one is trying to say there is that (my interpretation) "if you set the function in the header file itself, mark it as inline, because otherwise, when trying to include the header where the function was set in multiple source files, it will be copied to each source file and multiple definitions error occurs."

-1


If I create a test file. h, and another test.cpp, as the C++ compiler does to relate the test.cpp file to the test file. h, that is, what are the criteria used? What prevents the test settings. h in test.cpp from being replaced by others?

It is necessary to know the following things:

1) include places a header code in the same place as include. I mean, header is not source code to compile, it only contains code that will be embedded in true source code (these yes are compiled).

This means that the.cpp test, due to include, is the same as the one below (with the difference that include takes away your need to copy the entire header to the source code).

/* Teste.cpp: implementação de Teste.h.*/

// Começa o #include "teste.h"
/* teste.h */
#ifndef TESTE
#define TESTE

inline double cubo(double a);

#endif // TESTE
// Termina o #include "teste.h"

double cubo( double a )
{
    return a * a * a;
}

2) Defining something is creating this thing so that it can be used in the.cpp file where it was set. That’s what you did in the.cpp test, you set the cube function.

3) Declaring something is to warn that it exists (even in another file) and that it can be used. That’s what you did in the test. h, you declared the cube function. So, where you include the test. h you will be warning that you can henceforth in the source file use the function.

When you do the #include "teste.h" in the.cpp test, you are putting the statement of something that is soon after already defined there, ie it is unnecessary in the.cpp test. include is required only if the header declares something that will not be set or declared next in the same file, which is the case of main.cpp.

4) When compiling the source codes, there is the lynching process. Each source file gives rise to an object file with the symbols used in the code. These symbols of the object files are connected to each other in such a way that the definition in one source code can be used in another where the declaration is.

This means that the cube function has the existing cube symbol in main.cpp (where it is declared and used) and test.cpp (where it is defined and could be used, but is not), so the lynching enables main.cpp to have access to the test setting.cpp so that it can use the function. Without lynching, main.cpp has no access to the cube function defined in test.cpp.

Note: There are no substitutions of definitions. If the lincador finds two, the calls are ambiguous and therefore there is a semantic compilation error because the lincador will not know which definition should be used.

(Complement to the previous question) if we create a test file. h and implement it in a different filename, say, proof.cpp, yet the program compiles. How to explain this?

If you declare in proof.cpp, proof.cpp can use the function as well. But if you set it there while it is set in test.cpp and enable the lynching of both files, the definitions conflict, cause ambiguity and generate lynching error.

Why does the following code not compile? I get a Undefined error'.

If main.cpp uses a function but it is not defined, then this error appears. To find the definition, the.cpp test (which has the definition) has to be compiled to generate object code. This means that you are not compiling the.cpp test, so it is not being lynched. It is necessary to compile the two.

When implementing an inline function in a file. cpp, it makes some difference to remove the inline qualifier from the function definition, leaving only in the declaration?

It is necessary to define with inline. However, this effect also depends on compiler options, which may disable inline or even release inline for undefined functions in case the compiler deems it beneficial. If I’m not mistaken, the default is called a function from one file to another not generate inline code.

I read in various places that defining inline functions in header files helps prevent "multiple function definitions". Could explain how these "multiple definitions can occur"?

For example.

double Double( int x , double *p ){
    return *p = (double)x ;
}

double Double( int z , double *p ){
    *p = 2.0*z ;
    return *p ;
}

This is multiple definition. Two functions of the same signature (name and parameters Double(int,double*)), Even though they are different functions, they generate ambiguity. No problem define in different files (each file uses its function) unless the symbol is declared somewhere (because there is no known where to lynch that, there is the error that I addressed earlier).

I hope I made it clear. Otherwise, let me know.

  • Got it. Regarding items 1 and 2, I thought there was a match one to one between header files and source files. I now see that it is not so. If I create, a Myheader header. h, and declare in it three functions and implement each in its own file . cpp, the compiler itself will locate them and make the connection. So, "the compiler reads the header files and gets the list of statements in those files. Then search all the files indicated to compile the definitions for each of those statements".

  • Regarding item 3, the code compiles if I remove the qualifier inline. I believe I have not fully explained my question in this item. The question of item 3 lies in knowing because the code does not compile if I mark the function as inline.

  • More or less. The compiler optimizes the search by avoiding too many rereadings to speed up the compilation. It’s like this: (1) the compiler reads ". cpp" treating the ". h" as if they were part of it (thought include? leaves a little the ".cpp", reads that header included, then goes back to where it left off); (2) in reading the files, collects the necessary data of the symbols declared, defined and used; (3) evaluates the connections of the collected symbols.

  • Now as for the inline problem, I ran a test. I kept inline as it was, but took the include from test.cpp. Here, this compiled without error. I also tested with include, inline and extern before inline. Here, this also compiled without error. I don’t really understand what happens in these situations involving inline, I just know that there is something that changes the visibility or the function signature. One thing is certain: if it is not a bug, then there is a logic behind it.

  • Regarding my first comment, I am aware that it is not good practice to create a Myheader. h and implement his statements in multiple files. The same ideal is to have a header . h and a file . cpp with the same name, indicating that we are declaring and implementing the same feature set. That example was just to understand what happens internally.

Browser other questions tagged

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