Functions and Header Files
function
Overview
Purpose: Encapsulate a segment of frequently used code to reduce repetitive code.
A large program is generally divided into several modules, each of which implements specific functions.
function definition
A function definition typically involves 5 main steps:
- Return value type
- Function Name
- Parameter Table
- Function body statements
- return expression
Syntax:
返回值类型 函数名 (参数列表)
{
函数体语句
return表达式
}
运行结果: 此代码块不含 main 函数,是语法、接口或分文件示例,不能独立运行,因此没有终端输出。
- Return type: A function can return a value. In the function definition
- Function name: give the function a name
- Parameter list: the data passed in when using this function
- Function body statements: The code inside curly braces, which are the statements that need to be executed within the function.
- Return expressions are tied to the return type, and after a function completes execution, it returns the corresponding data.
Example: Define an addition function to add two numbers.
//函数定义
int add(int num1, int num2)
{
int sum = num1 + num2;
return sum;
}
运行结果: 此代码块不含 main 函数,是语法、接口或分文件示例,不能独立运行,因此没有终端输出。
Function call
Function: Use predefined functions
Syntax: 函数名(参数)
Example:
//函数定义
int add(int num1, int num2) //定义中的num1,num2称为形式参数,简称形参
{
int sum = num1 + num2;
return sum;
}
int main() {
int a = 10;
int b = 10;
//调用add函数
int sum = add(a, b);//调用时的a,b称为实际参数,简称实参
cout << "sum = " << sum << endl;
a = 100;
b = 100;
sum = add(a, b);
cout << "sum = " << sum << endl;
return 0;
}
运行结果:
sum = 20
sum = 200
Summary: In a function definition, parameters within parentheses are called formal parameters, while parameters passed during function invocation are called actual parameters.
Pass-by-value
- Pass-by-value means that when a function is called, the actual parameters pass their values to the formal parameters.
- When passing by value, ==if the parameter changes, it does not affect the argument==.
Example:
void swap(int num1, int num2)
{
cout << "交换前:" << endl;
cout << "num1 = " << num1 << endl;
cout << "num2 = " << num2 << endl;
int temp = num1;
num1 = num2;
num2 = temp;
cout << "交换后:" << endl;
cout << "num1 = " << num1 << endl;
cout << "num2 = " << num2 << endl;
//return ; 当函数声明时候,不需要返回值,可以不写return
}
int main() {
int a = 10;
int b = 20;
swap(a, b);
cout << "mian中的 a = " << a << endl;
cout << "mian中的 b = " << b << endl;
return 0;
}
运行结果:
交换前:
num1 = 10
num2 = 20
交换后:
num1 = 20
num2 = 10
mian中的 a = 10
mian中的 b = 20
Summary: When passing by value, the formal parameter cannot modify the actual argument.
Common Styles of Functions
There are 4 common function styles.
- no parameter no return
- function with parameters but no return value
- No parameters, but returns a value.
- with parameters and return values
Example:
//函数常见样式
//1、 无参无返
void test01()
{
//void a = 10; //无类型不可以创建变量,原因无法分配内存
cout << "this is test01" << endl;
//test01(); 函数调用
}
//2、 有参无返
void test02(int a)
{
cout << "this is test02" << endl;
cout << "a = " << a << endl;
}
//3、无参有返
int test03()
{
cout << "this is test03 " << endl;
return 10;
}
//4、有参有返
int test04(int a, int b)
{
cout << "this is test04 " << endl;
int sum = a + b;
return sum;
}
运行结果: 此代码块不含 main 函数,是语法、接口或分文件示例,不能独立运行,因此没有终端输出。
Function Declaration
Purpose: Specifies to the compiler the function name and how the function is to be called. The actual implementation of the function can be defined separately.
- Function declarations can be made multiple times, but a function can only have one definition.
Example:
//声明可以多次,定义只能一次
//声明
int max(int a, int b);
int max(int a, int b);
//定义
int max(int a, int b)
{
return a > b ? a : b;
}
int main() {
int a = 100;
int b = 200;
cout << max(a, b) << endl;
return 0;
}
运行结果:
200
Separating functions into different files
Purpose: To make the code structure clearer.
In the previous chapters, we've mostly been writing code inside src/main.cpp. This is good for learning syntax, but once the program gets a bit larger, it becomes messy.
Writing functions in separate files means splitting the code into:
- Header file
.h: Write function declarations. - source file
.cpp: Write function definition. main.cpp: calling a function.
Starting from C++ Development Environment and First Project, this tutorial has consistently used the same CMake template. By this point in the writing, your project likely still maintains this structure:
src/
├── CMakeLists.txt
├── main.cpp
├── lib1/
│ ├── CMakeLists.txt
│ ├── inc/lib1/eigen3_test.hpp
│ └── src/eigen3_test.cpp
└── lib2/
├── CMakeLists.txt
├── inc/lib2/eigen3_test.hpp
└── src/eigen3_test.cpp
lib1 and lib2 are two sample libraries that come with the template. In this section, we will organize them for the first time: delete the unused lib2, modify lib1 into our own swap library, and rename the template's example header and source files to swap.h and swap.cpp respectively. These will be used to demonstrate function file separation in this section.
After modification, the directory structure changed as follows:
src/
├── CMakeLists.txt
├── main.cpp
└── swap/
├── CMakeLists.txt
├── inc/swap/swap.h
└── src/swap.cpp
In other words:
- Remove the unused
lib2from this example. - Rename the
lib1directory toswap. - Rename the
inc/lib1directory toinc/swap, then rename theeigen3_test.hppinside it toswap.h. - Rename
src/eigen3_test.cpptosrc/swap.cpp.
Organize lib1 and lib2
First, delete lib2, it's not needed here.

- Rename the
lib1directory toswap: - Rename the
inc/lib1directory toinc/swap, and then rename theeigen3_test.hppwithin it toswap.h: - Rename
src/eigen3_test.cpptosrc/swap.cpp:

Edit swap.h
Open:
src/swap/inc/swap/swap.h
Write:
#include<iostream>
using namespace std;
void swap(int a, int b);

This is the first time we've separated function declarations into their own header file. swap.h is only responsible for informing other source files: there exists a function named swap that takes two int parameters in the project.
Additional note: In real engineering projects, it is generally discouraged to use
using namespace std;in header files, and function names likeswapshould be avoided as well, since the standard library already containsstd::swap. However, for now, let’s focus on understanding the workflow of "declare in the header, define in the source file, and call from the main function." Therefore, we’ll temporarily use this simple example code for teaching purposes.
Modify swap.cpp
Open:
src/swap/src/swap.cpp
Write:
#include "swap/swap.h"
void swap(int a, int b)
{
int temp = a;
a = b;
b = temp;
cout << "a = " << a << endl;
cout << "b = " << b << endl;
}

This #include "swap/swap.h" means: swap.cpp must see the function declaration before providing the function definition.
At this point, any VSCode errors can be disregarded. They occur because CMakeLists hasn't been modified yet, and clangd also hasn't been refreshed. You can ignore these code hint errors for now.
Modify main.cpp
Open:
src/main.cpp
Write:
#include "swap/swap.h"
int main()
{
int a = 100;
int b = 200;
swap(a, b);
return 0;
}
运行结果(与上面的 swap.cpp 一起编译并链接):
a = 200
b = 100

main.cpp only calls functions and no longer contains the actual implementation of the swap functions within itself.
Modify src/swap/CMakeLists.txt.
Open:
src/swap/CMakeLists.txt
This file originally came from lib1, so it still contains traces of lib1 and Eigen examples.
First, from the first line:
set(PREFIX "lib1")
Please provide the Simplified Chinese Markdown fragment you'd like me to translate.
set(PREFIX "swap")
这样 CMake 会创建一个名为:
swap_src_lib
library.
This example does not require Eigen, so remove the Eigen dependency from the Third-party dependencies block:
find_package(Eigen3 REQUIRED)
target_link_libraries(${PREFIX}_src_lib
PUBLIC
Eigen3::Eigen
)
Only modify the above two items; no need to modify the rest. Here is an introduction to some key points:
After organization, src/swap/CMakeLists.txt can be written as:
set(PREFIX "swap")
file(GLOB_RECURSE ${PREFIX}_SRC_LIST CONFIGURE_DEPENDS
"${CMAKE_CURRENT_LIST_DIR}/src/*.c"
"${CMAKE_CURRENT_LIST_DIR}/src/*.cpp"
)
add_library(${PREFIX}_src_lib SHARED
${${PREFIX}_SRC_LIST}
)
target_include_directories(${PREFIX}_src_lib
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/inc>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
target_link_libraries(${PREFIX}_src_lib
PUBLIC
project_options
PRIVATE
project_warnings
)
# ========================
# Third-party dependencies
# ========================
# =======
# Install
# =======
install(TARGETS ${PREFIX}_src_lib
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
install(DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/inc/"
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)
The most important lines here are:
file(GLOB_RECURSE ${PREFIX}_SRC_LIST CONFIGURE_DEPENDS
"${CMAKE_CURRENT_LIST_DIR}/src/*.c"
"${CMAKE_CURRENT_LIST_DIR}/src/*.cpp"
)
It will collect the .cpp files from inside src/swap/src/, so swap.cpp will be compiled.
Additionally:
target_include_directories(${PREFIX}_src_lib
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/inc>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
It adds src/swap/inc/ to the header file search path, so in the code you can write:
#include "swap/swap.h"
Note: Do not write as #include "inc/swap/swap.h". CMake has already told the compiler src/swap/inc/, so when including, continue writing from inc/ onwards, which means swap/swap.h.
The complete CMake syntax will be systematically explained in the CMake project template. For now, just know that "header files go into inc/, source files go into src/, and the library name is determined by PREFIX."
Modify src/CMakeLists.txt
Open:
src/CMakeLists.txt
Originally, the template contained:
add_subdirectory(lib1)
add_subdirectory(lib2)
Please provide the Simplified Chinese Markdown fragment you'd like me to translate.
add_subdirectory(swap)
The original template allowed lib1 to call lib2, but now lib2 is gone, so remove this part:
target_link_libraries(lib1_src_lib
PRIVATE
lib2_src_lib
)
Please specify which part you would like me to delete.
It turns out the template even links:
target_link_libraries(${PROJECT_NAME}
PRIVATE
lib1_src_lib
lib2_src_lib
)
Please provide the Simplified Chinese Markdown fragment you'd like me to translate.
target_link_libraries(${PROJECT_NAME}
PRIVATE
swap_src_lib
)
Only modify the three items mentioned above, everything else remains unchanged. Now, let me introduce the key points:
After organization, src/CMakeLists.txt can be written as:
add_executable(${PROJECT_NAME}
${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
)
target_link_libraries(${PROJECT_NAME}
PRIVATE
project_options
project_warnings
)
add_subdirectory(swap)
target_link_libraries(${PROJECT_NAME}
PRIVATE
swap_src_lib
)
set_target_properties(${PROJECT_NAME} PROPERTIES
INSTALL_RPATH "$ORIGIN/../${CMAKE_INSTALL_LIBDIR}"
)
install(TARGETS ${PROJECT_NAME}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
These two points are most critical:
add_subdirectory(swap)
This means: have CMake go into src/swap/ and read src/swap/CMakeLists.txt.
target_link_libraries(${PROJECT_NAME}
PRIVATE
swap_src_lib
)
This means that the main program has called the swap function, so the main program must link with swap_src_lib; otherwise, the linker will not be able to find the definition of the swap function.
Rebuild and run
Compile

At this point, the code suggestions from clangd will no longer show errors.

Then run:

Output similar to:
a = 200
b = 100
As can be seen, the functions in swap.cpp are indeed being called by the main program.
Core understanding of writing in separate files
In this template, splitting functions into separate files isn't just about dividing the files—you also need to ensure CMake recognizes which files belong to which library.
The corresponding relationship is as follows:
| file | effect |
|---|---|
src/swap/inc/swap/swap.h | Write function declarations so that other .cpp files know how to call them. |
src/swap/src/swap.cpp | Write function definitions and provide actual implementations. |
src/swap/CMakeLists.txt | Compile swap.cpp into swap_src_lib. |
src/CMakeLists.txt | Link swap_src_lib to the main program. |
src/main.cpp | Then call swap(a, b) |
If #include "swap/swap.h" is omitted, the compiler doesn't know the declaration of the swap function.
If add_subdirectory(swap) is omitted, CMake will not enter src/swap.
If missed:
target_link_libraries(${PROJECT_NAME}
PRIVATE
swap_src_lib
)
The linker cannot find the implementation of function swap.
Organization of Header Files
We just placed the declaration of the swap function into swap.h. Other source files, as long as they include this header file, can know which functions this library provides. These functions, types, and variables provided for use by external code are commonly referred to as the library's API.
Header files generally are responsible for containing:
- Function declaration.
- Declarations or definitions of types, structs, and classes.
- Necessary constant and variable declarations.
- Other header files required by these declarations.
Header files cannot be executed on their own. After modifying a header file, you need to recompile the .c or .cpp file that includes it to verify the changes.
Header files in a pure C++ project
The library in this chapter swap is implemented by swap.cpp and called by main.cpp. All source files are compiled as C++ code. Therefore, let's first look at the complete writing of a standard C++ header file.
Pure C++ projects are recommended to use the following header file template.
#ifndef __FILE_NAME_H_ // 防止头文件被重复包含,使用时要修改宏名
#define __FILE_NAME_H_
/* 头文件内容开始 */
// 在这里编写必要的预处理指令、类型定义、函数声明和变量声明
/* 头文件内容结束 */
#endif // __FILE_NAME_H_
When using the template, modify the protection macro based on the actual filename. For example:
swap.hcan use__SWAP_H_.camera.hppcan use__CAMERA_HPP_.
This chapter's swap.h can be organized as:
#ifndef __SWAP_H_
#define __SWAP_H_
#include <iostream>
using namespace std;
void swap(int a, int b);
#endif // __SWAP_H_
Now this is the most standardized form of a C++ header file.
After compilation and execution:

The #ifndef and #define at the beginning, along with the #endif at the end, form a header file protection macro. This ensures that even if the same header file is included indirectly multiple times, its contents are compiled only once, preventing issues such as duplicate definitions.
In pure C++ projects, the .hpp extension is also commonly used to emphasize that it is a C++ header file; .h can likewise be used. A project's own header files should generally retain their extensions, for example:
#include "swap/swap.h"
The names <iostream>, <string>, and similar in the standard library have no file extension—this is the naming convention dictated by the C++ standard. It does not imply that header files in your project should also omit extensions.
C interfaces and header files for mixed C/C++ projects
In a project, both .c and .cpp files can exist. For example, a C++ source file xxx.cpp can call functions from an .c file, and an main.c file can call functions from an .cpp file.
However, C and C++ compilers handle function names differently. Whenever a call crosses the boundary between C and C++, a compatible interface header file should be provided.
The extern "C" in header files only takes effect when processed by the C++ compiler. Its purpose is to tell the C++ compiler: these functions should be handled according to C language linkage rules.
For interfaces that need to be used between C and C++, the following header file template is recommended, and the file extension is suggested to be .h.
#ifndef __FILE_NAME_H_ // 防止头文件被重复包含,使用时要修改宏名
#define __FILE_NAME_H_
#ifdef __cplusplus // 当前文件被 C++ 编译器处理时才会成立
extern "C" {
#endif
/* 头文件内容开始 */
// 在这里编写必要的预处理指令、类型定义、函数声明和变量声明
/* 头文件内容结束 */
#ifdef __cplusplus
}
#endif
#endif // __FILE_NAME_H_
Here are two examples of independent project forms, both modified from the previously completed swap project. You can choose to practice only one; if practicing consecutively, you need to restore the filenames first according to the instructions in the second example.
main.cpp calls swap.c
This example retains the C++ implementation of main.cpp and changes the swap function to use a C language implementation.
First, rename swap.cpp to swap.c:
The main directory structure after modification is:
src/
├── CMakeLists.txt
├── main.cpp
└── swap/
├── CMakeLists.txt
├── inc/swap/swap.h
└── src/swap.c

Since src/swap/CMakeLists.txt will already collect both the .c and .cpp files, you only need to rename the files here without modifying the CMake file.
Modify src/swap/inc/swap/swap.h to make it includable by both C and C++.
#ifndef __SWAP_H_
#define __SWAP_H_
#ifdef __cplusplus
extern "C" {
#endif
void swap(int a, int b);
#ifdef __cplusplus
}
#endif
#endif // __SWAP_H_
Note that this header file may be processed by a C compiler, so do not include <iostream> in it or write using namespace std;.
Implementing swap in C within src/swap/src/swap.c:
#include "swap/swap.h"
#include <stdio.h>
void swap(int a, int b)
{
int temp = a;
a = b;
b = temp;
printf("a = %d\n", a);
printf("b = %d\n", b);
}
src/main.cpp remains a C++ source file and requires no changes:
#include "swap/swap.h"
int main()
{
int a = 100;
int b = 200;
swap(a, b);
return 0;
}
运行结果(与上面的 swap.c 一起编译并链接):
a = 200
b = 100

When compiling swap.c, the C compiler does not define __cplusplus, thus skipping extern "C". When compiling main.cpp, the C++ compiler will see extern "C", and therefore, following C language linkage rules, it will look for the swap function in swap.c.
main.c calls swap.cpp
Challenging aspects commonly encountered in STM32 HAL library,
This example flips the case: the entry file uses C language, while the swap library continues to be implemented in C++.
If you just finished the last example, first change swap.c back to swap.cpp:
Next, rename the entry file main.cpp to main.c:

The main directory structure after modification is:
src/
├── CMakeLists.txt
├── main.c
└── swap/
├── CMakeLists.txt
├── inc/swap/swap.h
└── src/swap.cpp
After the file name changes, you still need to open src/CMakeLists.txt and...
add_executable(${PROJECT_NAME}
${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
)
Please provide the Simplified Chinese Markdown fragment you'd like me to translate.
add_executable(${PROJECT_NAME}
${CMAKE_CURRENT_SOURCE_DIR}/main.c
)
src/swap/inc/swap/swap.h Continue using the compatible approach from earlier:
#ifndef __SWAP_H_
#define __SWAP_H_
#ifdef __cplusplus
extern "C" {
#endif
void swap(int a, int b);
#ifdef __cplusplus
}
#endif
#endif // __SWAP_H_
Use C++ to implement swap within src/swap/src/swap.cpp:
#include "swap/swap.h"
#include <iostream>
void swap(int a, int b)
{
int temp = a;
a = b;
b = temp;
std::cout << "a = " << a << std::endl;
std::cout << "b = " << b << std::endl;
}
swap.cpp must contain swap.h. After reading the header file, the C++ compiler will recognize that this swap function needs to be exposed externally according to C language linkage rules.
Finally, call it within src/main.c, and main.c still follows main.cpp without any modifications:
#include "swap/swap.h"
int main(void)
{
int a = 100;
int b = 200;
swap(a, b);
return 0;
}
Only the header file is used to call swap, and there's no need to understand advanced C++ syntax like std::cout. All C++ code remains within swap.cpp.
Only functions that need to cross the C/C++ boundary require this compatible implementation. Other .cpp files still follow regular C++ calling conventions among themselves.
The top-level CMakeLists.txt of the template has enabled C and C++ via LANGUAGES C CXX. CMake will use the C compiler to compile main.c, the C++ compiler to compile swap.cpp, and build swap.cpp into the swap_src_lib shared library within the template, before linking it to the main program.
extern "C" only changes the linkage rules, and does not automatically convert C++ code to C. Interfaces placed within it should use types and syntax that C can understand, avoiding C++-specific features such as function overloading, classes, templates, or C++ references.
main.c calls swap.cpp(advanced)
Challenging aspects commonly encountered in STM32 HAL library,
The previous example directly converted the swap function into a C interface. While this can work, it also introduces a limitation: swap.h must be comprehensible to the C compiler, so it cannot use C++-specific constructs such as namespaces, classes, templates, function overloading, or C++ references.
A more commonly used approach is to add an additional C interface layer:
main.cOnly call a function that C can understand, such ascpp_main().cpp_interface.cppis responsible for entering the world of C++.swap.cppKeep the regular C++ style; you can use namespaces.
The main directory structure after modification is:
src/
├── CMakeLists.txt
├── cpp_interface.cpp
├── cpp_interface.h
├── main.c
└── swap/
├── CMakeLists.txt
├── inc/swap/swap.h
└── src/swap.cpp
First, under src/, create cpp_interface.h:
#ifndef __CPP_INTERFACE_H_
#define __CPP_INTERFACE_H_
#ifdef __cplusplus
extern "C" {
#endif
int cpp_main(void);
#ifdef __cplusplus
}
#endif
#endif // __CPP_INTERFACE_H_
This header file is the C interface truly meant for main.c. It only declares cpp_main(void) with parameters and return values using types that C can understand.
Then modify src/main.c:
#include "cpp_interface.h"
int main(void)
{
return cpp_main();
}
At this point, main.c no longer contains swap/swap.h and no longer directly calls swap. It is only responsible for launching the C++ side cpp_main().
Now let's change src/swap/inc/swap/swap.h back to a regular C++ header file and add a namespace to swap:
#ifndef __SWAP_H_
#define __SWAP_H_
namespace swap_demo
{
void swap(int a, int b);
}
#endif // __SWAP_H_
Note, this swap.h is no longer a C header file. It contains namespace, so it can't be directly included by main.c anymore.
Here doesn't need to be added to swap.h:
#ifdef __cplusplus
extern "C" {
#endif
The reason is: swap_demo::swap is just an ordinary C++ function, and we want it to retain the C++ namespace convention. extern "C" should only be placed on the interface layer that C code actually calls, which is the cpp_main(void) in the previously mentioned cpp_interface.h.
In other words, the advanced version contains two header files:
| Header file | Who will include | Whether extern "C" is needed. |
|---|---|---|
cpp_interface.h | main.c and cpp_interface.cpp | Needed because it's a C/C++ boundary. |
swap/swap.h | swap.cpp and cpp_interface.cpp | 不需要,因为它是纯C++头文件 |
Continue modifying src/swap/src/swap.cpp:
#include "swap/swap.h"
#include <iostream>
namespace swap_demo
{
void swap(int a, int b)
{
int temp = a;
a = b;
b = temp;
std::cout << "a = " << a << std::endl;
std::cout << "b = " << b << std::endl;
}
}
Finally, create src/cpp_interface.cpp:
#include "cpp_interface.h"
#include "swap/swap.h"
int cpp_main(void)
{
int a = 100;
int b = 200;
swap_demo::swap(a, b);
return 0;
}
cpp_interface.cpp serves as the interface between C and C++. It includes cpp_interface.h, so cpp_main() will be exposed using C language linkage rules. It is itself a .cpp file, allowing internal calls to C++ constructs like swap_demo::swap(a, b).
After adding the file, you still need to open src/CMakeLists.txt and include cpp_interface.cpp in the main program:
add_executable(${PROJECT_NAME}
${CMAKE_CURRENT_SOURCE_DIR}/main.c
${CMAKE_CURRENT_SOURCE_DIR}/cpp_interface.cpp
)
Here, you don't need to put cpp_interface.h into add_executable(). CMake is mainly responsible for handing source files like .c, .cpp, etc., to the compiler for compilation; header files themselves won't be compiled into an object file separately.
cpp_interface.h is found in the code through #include:
#include "cpp_interface.h"
Because main.c, cpp_interface.cpp, and cpp_interface.h are all in the same directory as src/, when they are enclosed in double quotes here, the compiler can locate them from the directory of the current source file.
If you move cpp_interface.h into a separate inc/ directory in the future, you would need to use target_include_directories() again to add that directory to the header file search path. In the current example, everything is in the same directory level, so no additional CMake modifications are needed.
src/swap/CMakeLists.txt does not need to be modified, as it already collects the .cpp files from the src/swap/src/ directory, and swap.cpp will still be compiled into swap_src_lib.
After compiling and running, the output still resembles:
a = 200
b = 100
The focus of this advanced approach is: extern "C" is only placed on the outermost, simplest interface, which is cpp_main(void). The actual C++ code goes behind cpp_interface.cpp, where swap can use namespaces, and future C++ features like classes, templates, and function overloading can also be used—provided these C++-specific elements are not directly exposed to main.c.
#include <...> and #include "..."
Both methods are used for including header files, but they are commonly used in different scenarios:
#include <iostream>
#include <opencv2/opencv.hpp>
Angle brackets are typically used for standard library or already installed third-party library headers.
#include "swap/swap.h"
Double quotes are usually used for header files in the current project. This can be written as "swap/swap.h" because CMake has already added src/swap/inc/ to the compiler's header file search path.
Whether using C or C++, header files should be equipped with protection macros; only when a header file serves as an interface between C and C++ should the extern "C" compatibility section be added within the protection macro.