Article directory
How Compiler work
original Math.cpp
:
int Multiply(int a, int b) {
int result = a * b;
return result;
}
Now the demo needs to be split into two files:
EndBrance.h
}
Math.cpp
int Multiply(int a, int b) {
int result = a * b;
return result;
#include "EndBrance.h"
Compile Math.cpp
without error.
The role of the compiler: open EndBrance.h
the file, copy and paste all the contents inside to #include "EndBrance.h"
the location.
See why by preprocessing the output file
Modify the project property configuration (after configuring the test, remember to cancel the setting):
Recompile Math.cpp
, a file will be generated in the Debug directory Math.i
, open to view the content:
It can be seen that the content generated by the compiler Math.cpp
is contained in the source code, and the compiler embeds #include "EndBrance.h"
the in its file into the location.)
#include "EndBrance.h"
Similarly, modify the code and check again
such as using#define
#define INTERGER int
INTERGER Multiply(int a, int b) {
INTERGER result = a * b;
return result;
}
After recompiling:
For example, use #if
, compile and viewMath.i
#if 0
int Multiply(int a, int b) {
int result = a * b;
return result;
}
#endif
For example, use it #include <iostream>
, check it after compiling, there are more than 50,000 lines in it, and the last is the code I wrote myself. This is because iostream
other file codes are included in .
How Linker work
LNK1561
Math.cpp
#include <iostream>
void Log(const char* message) {
std::cout << message << std::endl;
}
int Multiply(int a, int b) {
Log("Multiply");
return a * b;
}
Compile directly, and an error will appear: LNK1561, entry point must be defined. LNKxxx indicates that an error is reported in linking, and Cxxx indicates an error is reported in compilation.
Through project properties, you can customize an entry. The entry point is not necessarily the main function, usually the main function.
Add the main function, and recompile will be fine.
int main() {
std::cout << Multiply(3, 5) << std::endl;
std::cin.get();
}
LNK2019
If you change Log.cpp
the name of the Log function in the file to Logger, and then just compile (Crtl+F7) Math.cpp
, no error will be reported, and the link has not been used in this process.
Then, compile the entire project (Ctrl+F5), and an LN2019 error will appear
1>------ 已启动生成: 项目: demo_include, 配置: Debug Win32 ------
1>Math.obj : error LNK2019: 无法解析的外部符号 "void __cdecl Log(char const *)" (?Log@@YAXPBD@Z),该符号在函数 "int __cdecl Multiply(int,int)" (?Multiply@@YAHHH@Z) 中被引用
1>E:\keeplearning\CppCode\VS2017\demo_include\Debug\demo_include.exe : fatal error LNK1120: 1 个无法解析的外部命令
1>已完成生成项目“demo_include.vcxproj”的操作 - 失败。
========== 生成: 成功 0 个,失败 1 个,最新 0 个,跳过 0 个 ==========
Try the following:
-
After commenting out
Log("Multiply");
, compile the entire project and compile successfully#include <iostream> void Log(const char *); int Multiply(int a, int b) { // Log("Multiply"); return a * b; } int main() { std::cout << Multiply(3, 5) << std::endl; std::cin.get(); }
-
After commenting out
main
the call in the function, compile the entire project, and the compilation fails#include <iostream> void Log(const char *); int Multiply(int a, int b) { Log("Multiply"); return a * b; } int main() { // std::cout << Multiply(3, 5) << std::endl; std::cin.get(); }
1>------ 已启动生成: 项目: demo_include, 配置: Debug Win32 ------ 1>Math.obj : error LNK2019: 无法解析的外部符号 "void __cdecl Log(char const *)" (?Log@@YAXPBD@Z),该符号在函数 "int __cdecl Multiply(int,int)" (?Multiply@@YAHHH@Z) 中被引用 1>E:\keeplearning\CppCode\VS2017\demo_include\Debug\demo_include.exe : fatal error LNK1120: 1 个无法解析的外部命令 1>已完成生成项目“demo_include.vcxproj”的操作 - 失败。 ========== 生成: 成功 0 个,失败 1 个,最新 0 个,跳过 0 个 ==========
The reason is that even if the Multiply function is not actually called in this file, it may be used in other files to a certain extent, so the linker needs to link.
-
If you tell the linker that the Multiply function is only used in
Math.cpp
and will not be used in other files, can you not link? Of course, it is also possible. At this time, change Multiply to static (meaning it is only used in this file), recompile the entire project, and there will be no link error.#include <iostream> void Log(const char *); static int Multiply(int a, int b) { Log("Multiply"); return a * b; } int main() { // std::cout << Multiply(3, 5) << std::endl; std::cin.get(); }
Of course, if on this basis,
// std::cout << Multiply(3, 5) << std::endl;
the opening comment in the main function is added, and then the project is compiled, there will also be an error.
In addition to changing Log.cpp
the name of the Log function in the file to Logger, if other changes are made, there will be a link error and the compilation will fail:
#include <iostream>
int Log(const char* message) {
// 改变返回值类型
std::cout << message << std::endl;
return 0;
}
#include <iostream>
void Log(const char* message, int level) {
// 改变入参个数
std::cout << message << std::endl;
}
LNK2005
Check whether there are functions or variables with the same and repeated names or features. For example, two functions with the same name have the same return value and input parameters. At this time, the linker does not know which one to link.
-
scene 1
Log.cpp
#include <iostream> void Log(const char* message) { std::cout << message << std::endl; }
Math.cpp
#include <iostream> void Log(const char *); void Log(const char* message) { std::cout << message << std::endl; } int Multiply(int a, int b) { Log("Multiply"); return a * b; } int main() { std::cout << Multiply(3, 5) << std::endl; std::cin.get(); }
Programming project, error:
1>------ 已启动全部重新生成: 项目: demo_include, 配置: Debug Win32 ------ 1>Log.cpp 1>Math.cpp 1>正在生成代码... 1>Math.obj : error LNK2005: "void __cdecl Log(char const *)" (?Log@@YAXPBD@Z) 已经在 Log.obj 中定义 1>E:\keeplearning\CppCode\VS2017\demo_include\Debug\demo_include.exe : fatal error LNK1169: 找到一个或多个多重定义的符号 1>已完成生成项目“demo_include.vcxproj”的操作 - 失败。 ========== 全部重新生成: 成功 0 个,失败 1 个,跳过 0 个 ==========
-
scene 2
Log.h
#pragma once void Log(const char* message) { std::cout << message << std::endl; }
Log.cpp
#include <iostream> #include "Log.h" void InitLog() { Log("Initialized Log"); }
Math.cpp
#include <iostream> #include "Log.h" static int Multiply(int a, int b) { Log("Multiply"); return a * b; } int main() { std::cout << Multiply(3, 5) << std::endl; std::cin.get(); }
Compile the project and report an error
1>------ 已启动生成: 项目: demo_include, 配置: Debug Win32 ------ 1>Log.cpp 1>Math.obj : error LNK2005: "void __cdecl Log(char const *)" (?Log@@YAXPBD@Z) 已经在 Log.obj 中定义 1>E:\keeplearning\CppCode\VS2017\demo_include\Debug\demo_include.exe : fatal error LNK1169: 找到一个或多个多重定义的符号 1>已完成生成项目“demo_include.vcxproj”的操作 - 失败。 ========== 生成: 成功 0 个,失败 1 个,最新 0 个,跳过 0 个 ==========
#include
How the statement works: When including a header file, we just put the contents of the header file where the statement exists.Therefore, writing both in
Log.cpp
and will lead to repeated definitions of the Log function, resulting in the same problem as Scenario 1.Math.cpp
#include "Log.h"
The solution to this problem:
-
method 1
Change
Log.h
the method in to static, other files remain unchanged, and the compilation project passes#pragma once static void Log(const char* message) { std::cout << message << std::endl; }
-
Method 2
Replace
Log.h
the method in inline with other files unchanged#pragma once inline void Log(const char* message) { std::cout << message << std::endl; }
-
Method 3
Log.h
#pragma once void Log(const char* message);
Log.cpp
#include <iostream> #include "Log.h" void Log(const char* message) { std::cout << message << std::endl; } void InitLog() { Log("Initialized Log"); }
Math.cpp
#include <iostream> #include "Log.h" int Multiply(int a, int b) { Log("Multiply"); return a * b; } int main() { std::cout << Multiply(3, 5) << std::endl; std::cin.get(); }