ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

C++新手项目框架搭建指南:从零构建标准化开发环境

C++新手项目框架搭建指南:从零构建标准化开发环境 1. 项目概述为什么新手需要一个“框架”如果你刚接触C打开编译器面对一个空白的main.cpp文件是不是常常感到一丝迷茫从哪开始写头文件怎么写代码结构怎么组织编译命令又是什么这种感觉我太熟悉了十几年前我刚学C时也是从“Hello World”之后就卡在了如何构建一个像样项目的门槛上。很多教程一上来就讲语法变量、循环、指针但很少告诉你如何把这些零散的语法砖块砌成一栋能“住人”的程序大厦。这就是“框架”的意义——它不是一个具体的库比如Qt、Boost而是一个项目脚手架一个标准化的起点。这个“框架”教程就是要帮你解决从“会写代码片段”到“能组织完整项目”的跨越。它包含了你项目最基础的骨架源代码和头文件如何分离、如何编写跨平台的构建脚本比如CMake、如何管理第三方依赖、如何设置一个清晰的目录结构以及如何配置你的集成开发环境IDE。有了这个框架你以后每开始一个新项目无论是写一个命令行工具、一个小游戏还是一个网络服务器都可以直接在这个基础上“填空”把精力集中在核心逻辑上而不是每次都从零开始搭建环境、解决链接错误。这就像学做菜先学会怎么开火、怎么用锅、怎么备料框架再去学具体的菜谱算法、功能效率会高得多。2. 新手框架的核心组件拆解一个对新手友好的C项目框架其核心目标应该是降低认知负担和减少环境配置的摩擦。它不需要像大型商业框架那样功能繁杂但必须稳固、清晰、可扩展。下面我们来拆解它的几个核心部分。2.1 目录结构一切井然有序的开始混乱的目录是项目失控的开端。一个好的结构能让你和你的合作者未来的你也是合作者一眼看懂项目的布局。对于新手项目我推荐一个简洁但足够用的结构my_cpp_project/ ├── CMakeLists.txt # 项目总构建脚本 ├── README.md # 项目说明文档 ├── .gitignore # Git版本控制忽略文件列表 ├── src/ # 源代码目录 │ ├── main.cpp # 程序入口 │ ├── core/ # 核心业务逻辑模块 │ │ ├── Calculator.cpp │ │ └── Calculator.h │ └── utils/ # 工具函数模块 │ ├── Logger.cpp │ └── Logger.h ├── include/ # 对外公开的头文件可选小型项目可与src合并 │ └── my_project/ # 防止头文件命名冲突 │ └── public_api.h ├── tests/ # 单元测试目录 │ ├── test_calculator.cpp │ └── CMakeLists.txt # 测试专用的构建配置 ├── third_party/ # 第三方库可选通常用包管理器管理 ├── build/ # 构建输出目录由CMake生成应在.gitignore中 └── scripts/ # 辅助脚本如一键编译、清理等 └── build_and_run.sh为什么这么设计src/和include/分离这是一种经典做法。src放实现.cppinclude放对外接口.h。对于小型个人项目你也可以把.h和.cpp都放在src里按模块文件夹组织。分离的好处是当你的代码未来可能作为库给别人用时他们只需要include目录里的头文件。模块化子目录像core/、utils/这样的文件夹是根据功能划分的模块。这强迫你思考代码的职责分离避免把所有函数都堆在main.cpp里。独立的tests/目录测试代码和业务代码分离是良好实践。为测试单独写一个CMakeLists.txt可以灵活控制测试的编译选项和依赖。build/目录这是“Out-of-source build”的关键。所有编译生成的中间文件.o,.obj和最终可执行文件都放在这里不会污染源代码目录。清理时直接删除build/文件夹即可。实操心得一开始就养成使用build目录的习惯。在项目根目录下永远执行mkdir build cd build cmake .. make。这能帮你避免无数因残留的旧编译文件导致的诡异错误。2.2 CMake现代C项目的构建基石对于新手来说手动写g -Iinclude -Llib src/*.cpp -o app这种命令既繁琐又容易出错而且无法跨平台Windows上用不了。CMake是一个构建系统生成器它让你用一套相对高级的语法描述项目然后它能为你生成对应平台Windows的Visual Studio项目、Linux的Makefile、macOS的Xcode项目的本地构建文件。一个最基础、但功能齐全的CMakeLists.txt应该长这样# 1. 指定CMake最低版本和要求 cmake_minimum_required(VERSION 3.15) # 设置项目名称和版本以及使用的编程语言 project(MyCppProject VERSION 1.0.0 LANGUAGES CXX) # 2. 设置C标准这是新手最容易忽略但最重要的一步 set(CMAKE_CXX_STANDARD 17) # 使用C17标准 set(CMAKE_CXX_STANDARD_REQUIRED ON) # 必须支持该标准 set(CMAKE_CXX_EXTENSIONS OFF) # 禁用编译器扩展保证代码可移植性 # 3. 可执行文件输出到 build/bin 目录库文件输出到 build/lib set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) # 4. 包含头文件目录 # 将当前源代码目录CMAKE_CURRENT_SOURCE_DIR和其下的include目录加入头文件搜索路径 include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src) # 如果头文件在src里 # 5. 查找源代码文件 # 递归地收集src目录下所有的.cpp文件赋值给变量SOURCES file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS src/*.cpp) # 6. 添加可执行目标 add_executable(${PROJECT_NAME} ${SOURCES}) # 7. 设置编译选项根据平台和编译器 if(MSVC) # 如果是微软Visual Studio编译器 target_compile_options(${PROJECT_NAME} PRIVATE /W4 /WX) # 开启所有警告并视警告为错误 else() # 对于GCC或Clang target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Werror -pedantic) endif() # 8. 链接库如果需要 # 例如如果你使用了线程库 # target_link_libraries(${PROJECT_NAME} PRIVATE pthread) # 9. 启用测试可选 enable_testing() # 添加一个测试 # add_test(NAME MyTest COMMAND ${PROJECT_NAME} --test)关键点解析C标准set(CMAKE_CXX_STANDARD 17)这行至关重要。它告诉编译器使用C17规范来编译你的代码。C11/14/17/20带来了许多现代、安全的特性如智能指针、范围for循环、结构化绑定能极大提升开发效率和代码质量。作为新手直接从C17起步是很好的选择。file(GLOB_RECURSE ...)这是一个方便但略有争议的命令。它自动匹配所有.cpp文件省去了手动列出的麻烦。缺点是如果你在CMake运行后新增了.cpp文件需要重新运行CMakeCONFIGURE_DEPENDS参数能在一定程度上缓解此问题。对于新手小项目用GLOB问题不大对于大型项目更推荐显式地列出所有源文件。编译警告即错误-Werror(GCC/Clang) 或/WX(MSVC) 选项会将所有警告视为编译错误。这听起来很严格但它能强迫你写出更干净、无警告的代码是培养良好编码习惯的利器。2.3 基础代码模块从“Hello World”到“有模有样”有了目录和构建系统我们来看看框架里的代码应该怎么写。我们从一个增强版的“Hello World”开始。src/main.cpp- 程序入口/** * file main.cpp * brief 项目主入口文件 */ #include iostream #include “core/Calculator.h” // 引入自定义模块 #include “utils/Logger.h” int main(int argc, char* argv[]) { // 初始化日志系统示例 Logger::Init(); LOG_INFO(“程序启动。”); // 处理命令行参数可选 for (int i 0; i argc; i) { LOG_DEBUG(“参数 {}: {}“, i, argv[i]); } // 使用核心模块 Calculator calc; int result calc.Add(10, 20); std::cout “10 20 “ result std::endl; LOG_INFO(“程序正常退出。”); return 0; }src/core/Calculator.h- 核心模块头文件// 防止头文件被多次包含的经典宏 #ifndef MY_CPP_PROJECT_CALCULATOR_H #define MY_CPP_PROJECT_CALCULATOR_H /** * class Calculator * brief 一个简单的计算器类用于演示模块化设计。 */ class Calculator { public: Calculator() default; // 使用编译器生成的默认构造函数 ~Calculator() default; // 默认析构函数 // 禁止拷贝构造和拷贝赋值Rule of Five的简化应用 Calculator(const Calculator) delete; Calculator operator(const Calculator) delete; /// brief 两数相加 int Add(int a, int b); /// brief 两数相减 int Subtract(int a, int b); /// brief 两数相乘 int Multiply(int a, int b); /// brief 两数相除注意除零检查 /// return 如果除数为0返回0实际项目应使用异常或错误码 double Divide(int a, int b); }; #endif // MY_CPP_PROJECT_CALCULATOR_Hsrc/core/Calculator.cpp- 核心模块实现#include “core/Calculator.h” #include stdexcept // 标准异常头文件 #include “utils/Logger.h” // 使用日志 int Calculator::Add(int a, int b) { LOG_DEBUG(“执行加法: {} {}“, a, b); return a b; } int Calculator::Subtract(int a, int b) { return a - b; } int Calculator::Multiply(int a, int b) { return a * b; } double Calculator::Divide(int a, int b) { if (b 0) { LOG_ERROR(“除法错误除数为零”); // 更好的做法是抛出异常throw std::invalid_argument(“Divisor cannot be zero.”); return 0.0; // 简单处理返回0 } return static_castdouble(a) / b; // 注意类型转换以得到浮点数结果 }src/utils/Logger.h- 工具模块头文件#ifndef MY_CPP_PROJECT_LOGGER_H #define MY_CPP_PROJECT_LOGGER_H #include string #include iostream /** * namespace Logger * brief 简单的日志工具类控制台输出。 * 在实际项目中可以考虑使用spdlog、glog等成熟库。 */ namespace Logger { // 日志级别 enum class Level { DEBUG, INFO, WARN, ERROR }; /// brief 初始化日志系统此处预留可为空 void Init(); /// brief 记录日志 void Log(Level level, const std::string message); // 便捷宏可选但方便使用 #define LOG_DEBUG(msg) Logger::Log(Logger::Level::DEBUG, msg) #define LOG_INFO(msg) Logger::Log(Logger::Level::INFO, msg) #define LOG_WARN(msg) Logger::Log(Logger::Level::WARN, msg) #define LOG_ERROR(msg) Logger::Log(Logger::Level::ERROR, msg) } // namespace Logger #endifsrc/utils/Logger.cpp- 工具模块实现#include “utils/Logger.h” #include chrono #include iomanip void Logger::Init() { // 可以在这里初始化文件流、设置日志格式等 std::cout “[Logger] 日志系统初始化完成。“ std::endl; } void Logger::Log(Level level, const std::string message) { auto now std::chrono::system_clock::now(); auto time std::chrono::system_clock::to_time_t(now); // 使用线程安全的localtime_rLinux/macOS或localtime_sWindows std::tm tmBuf{}; #ifdef _WIN32 localtime_s(tmBuf, time); #else localtime_r(time, tmBuf); #endif std::cout std::put_time(tmBuf, “[%Y-%m-%d %H:%M:%S] “); switch (level) { case Level::DEBUG: std::cout “[DEBUG] “; break; case Level::INFO: std::cout “[INFO] “; break; case Level::WARN: std::cout “[WARN] “; break; case Level::ERROR: std::cout “[ERROR] “; break; } std::cout message std::endl; }这个代码框架展示了几个关键实践头文件守卫#ifndef ... #define ... #endif防止因头文件被多次包含而导致的重复定义错误。文档注释使用///或/** */为类和方法添加简要说明。这对自己和他人都是好习惯。显式删除拷贝操作在Calculator类中我们删除了拷贝构造函数和拷贝赋值运算符。对于简单的、不管理资源的类这可以防止意外的拷贝行为。这是学习“Rule of Three/Five/Zero”的起点。命名空间将工具类Logger放在命名空间里避免全局命名污染。条件编译在Logger.cpp中我们使用#ifdef _WIN32来区分Windows和其他平台的本地时间函数这是编写跨平台代码的常见技巧。简单的日志系统自己实现一个最基础的日志工具比直接用std::cout更结构化也便于未来替换成专业日志库。3. 环境配置与一键构建框架搭好了怎么把它跑起来这里给出从零开始在Windows使用Visual Studio和Linux/macOS使用GCC/Clang上的完整流程。3.1 开发环境准备Windows (Visual Studio 2022 Community Edition)安装VS2022去官网下载安装程序在“工作负载”中勾选“使用C的桌面开发”。这会安装MSVC编译器、CMake和Git。安装CMake可选如果VS安装时没带或版本旧去CMake官网下载安装并确保将cmake.exe所在目录加入系统PATH。安装Git同上如果VS没带去Git官网下载安装。Linux (Ubuntu/Debian)sudo apt update sudo apt install build-essential cmake git # build-essential 包含了gcc, g, make等工具macOS# 安装Xcode Command Line Tools包含Clang和make xcode-select --install # 使用Homebrew安装CMake和Git如果未安装 brew install cmake git3.2 使用框架创建新项目假设你的框架代码已经放在GitHub上一个叫cpp-starter-template的仓库里。# 1. 克隆框架模板或直接复制文件夹 git clone https://github.com/yourname/cpp-starter-template.git my_new_project cd my_new_project # 2. 重命名项目修改CMakeLists.txt中的project名称 # 用文本编辑器打开CMakeLists.txt将第一行的project(MyCppProject ...)改为project(my_new_project ...) # 3. 执行构建Out-of-source build mkdir build cd build cmake .. # 生成构建文件 # 在Windows上默认会生成Visual Studio的.sln文件。如果你想生成Ninja构建更快 # cmake -G “Ninja” .. # 在Linux/macOS上默认生成Makefile。 # 4. 编译 # 如果上一步生成的是Makefile make -j4 # -j4表示用4个线程并行编译加快速度 # 如果上一步生成的是Ninja构建文件 ninja # 如果是在Windows的VS开发者命令行中且生成了.sln可以用 # cmake --build . --config Release # 5. 运行程序 # 可执行文件会在 build/bin/ 目录下由CMakeLists.txt中的设置决定 ./bin/MyCppProject # Linux/macOS # 或者 .\bin\Release\MyCppProject.exe (Windows, 如果使用VS的Release配置)3.3 集成开发环境IDE配置Visual Studio Code (跨平台推荐)安装VSCode并安装扩展C/C(Microsoft),CMake(twxs),CMake Tools(Microsoft)。用VSCode打开项目根目录。按下CtrlShiftP输入“CMake: Configure”选择你的编译器如GCC或MSVC。配置完成后底部状态栏会出现构建按钮。你可以直接点击构建、运行、调试。在.vscode文件夹下创建launch.json和tasks.json可以实现更强大的调试功能。CLion (JetBrains出品专业且强大)直接用CLion打开项目根目录包含CMakeLists.txt的目录。CLion会自动识别CMake项目并完成配置。右上角有绿色的运行/调试按钮可以直接使用体验非常流畅。Visual Studio (Windows)用VS直接打开build目录下生成的.sln解决方案文件。或者在VS中选择“打开本地文件夹”指向项目根目录VS的CMake集成功能会自动识别并配置。踩坑记录新手最容易犯的错误之一是在源代码目录里直接编译导致生成的.o文件和可执行文件散落各处。务必坚持“out-of-source build”即在独立的build目录中操作。另一个常见错误是修改代码后只运行了make但新增的.cpp文件没有在CMakeLists.txt中更新如果用了file(GLOB)且没加CONFIGURE_DEPENDS或者手动列出了文件列表但忘了加。此时需要重新运行cmake ..。4. 框架的扩展与进阶指引这个基础框架可以随着你技能的增长而不断进化。这里提供几个关键的扩展方向。4.1 引入第三方库以spdlog和fmt为例几乎没有一个现实项目不依赖外部库。使用包管理器如vcpkg, Conan是现代C的最佳实践。这里以vcpkg为例演示如何集成spdlog一个优秀的日志库和fmt一个现代化的格式化库。步骤1安装vcpkggit clone https://github.com/microsoft/vcpkg.git cd vcpkg ./bootstrap-vcpkg.bat # Windows # 或 ./bootstrap-vcpkg.sh # Linux/macOS步骤2安装库./vcpkg install spdlog fmtvcpkg会自动从源码编译这些库并处理好依赖关系。步骤3修改CMakeLists.txt以使用vcpkg在项目根目录的CMakeLists.txt最前面添加以下内容告诉CMake使用vcpkg提供的工具链文件。# 在 project() 命令之前设置 # 假设vcpkg安装在 D:/dev/vcpkg set(CMAKE_TOOLCHAIN_FILE “D:/dev/vcpkg/scripts/buildsystems/vcpkg.cmake” CACHE STRING “Vcpkg toolchain file”)然后在add_executable之后使用find_package和target_link_libraries来链接库。# ... 之前的CMake内容 ... add_executable(${PROJECT_NAME} ${SOURCES}) # 查找spdlog和fmt库 find_package(spdlog CONFIG REQUIRED) find_package(fmt CONFIG REQUIRED) # 将库链接到你的可执行文件 target_link_libraries(${PROJECT_NAME} PRIVATE spdlog::spdlog fmt::fmt) # ... 编译选项等 ...步骤4在代码中使用spdlog现在你可以把之前自己写的Logger.h/cpp替换成更强大的spdlog了。src/main.cpp:#include spdlog/spdlog.h #include spdlog/sinks/basic_file_sink.h // 文件输出 #include “core/Calculator.h” int main() { // 初始化spdlog同时输出到控制台和文件 auto console_sink std::make_sharedspdlog::sinks::stdout_color_sink_mt(); auto file_sink std::make_sharedspdlog::sinks::basic_file_sink_mt(“logs/my_app.log”, true); spdlog::logger logger(“multi_sink”, {console_sink, file_sink}); spdlog::set_default_logger(std::make_sharedspdlog::logger(logger)); spdlog::set_level(spdlog::level::debug); // 设置全局日志级别 spdlog::set_pattern(“[%Y-%m-%d %H:%M:%S.%e] [%^%l%$] %v”); // 设置格式 SPDLOG_INFO(“程序启动使用spdlog记录日志。”); Calculator calc; int result calc.Add(5, 3); SPDLOG_DEBUG(“5 3 {}“, result); // 使用fmt的格式化语法{}是占位符 SPDLOG_INFO(“程序退出。”); return 0; }通过这个例子你学会了如何使用包管理器引入外部依赖这是项目从“玩具”走向“实用”的关键一步。4.2 添加单元测试使用Google Test测试是保证代码质量的重要手段。Google Test (gtest) 是C领域最流行的单元测试框架之一。步骤1通过vcpkg安装gtest./vcpkg install gtest步骤2在项目中创建测试在tests/目录下创建CMakeLists.txt# tests/CMakeLists.txt cmake_minimum_required(VERSION 3.15) project(MyCppProjectTests) # 查找GoogleTest find_package(GTest CONFIG REQUIRED) # 添加一个测试可执行文件 add_executable(run_all_tests test_calculator.cpp # 可以添加更多测试文件 ) # 链接gtest库和你的主项目库如果需要测试内部函数可能需要将主项目编译为库 target_link_libraries(run_all_tests PRIVATE GTest::gtest GTest::gtest_main) # 如果你的主项目代码编译成了库比如叫 my_lib需要链接它 # target_link_libraries(run_all_tests PRIVATE GTest::gtest GTest::gtest_main my_lib) # 将测试目录添加到头文件搜索路径 target_include_directories(run_all_tests PRIVATE ${CMAKE_SOURCE_DIR}/src) # 告诉CTest这是一个测试 include(GoogleTest) gtest_discover_tests(run_all_tests)步骤3编写测试代码tests/test_calculator.cpp:#include gtest/gtest.h #include “core/Calculator.h” // 测试夹具Fixture用于设置测试环境 class CalculatorTest : public ::testing::Test { protected: Calculator calc; // 每个测试用例都会有一个新的calc对象 }; // 测试加法 TEST_F(CalculatorTest, AddPositiveNumbers) { EXPECT_EQ(calc.Add(2, 3), 5); EXPECT_EQ(calc.Add(0, 0), 0); EXPECT_EQ(calc.Add(-1, 5), 4); } // 测试除法 TEST_F(CalculatorTest, DivideByNonZero) { EXPECT_DOUBLE_EQ(calc.Divide(10, 2), 5.0); EXPECT_NEAR(calc.Divide(1, 3), 0.333333, 1e-6); // 浮点数比较使用NEAR } TEST_F(CalculatorTest, DivideByZero) { // 测试除零行为。因为我们当前实现返回0可以这样测试。 // 如果改为抛出异常则应使用 EXPECT_THROW。 EXPECT_DOUBLE_EQ(calc.Divide(5, 0), 0.0); } int main(int argc, char **argv) { ::testing::InitGoogleTest(argc, argv); return RUN_ALL_TESTS(); }步骤4在主CMakeLists.txt中包含测试在项目根目录的CMakeLists.txt末尾添加# 启用测试 enable_testing() # 添加子目录tests add_subdirectory(tests)步骤5编译并运行测试cd build cmake .. make # 或 ninja ctest --output-on-failure # 运行所有测试并打印失败详情 # 或者直接运行测试可执行文件 ./tests/run_all_tests现在每次修改代码后运行测试就能快速验证功能是否被破坏。这是迈向“测试驱动开发”(TDD)的第一步。4.3 代码格式化与静态分析打造高质量代码习惯一致的代码风格和提前发现潜在错误对个人和团队都至关重要。我们可以集成clang-format和clang-tidy。clang-format (代码格式化)在项目根目录创建.clang-format文件。可以从LLVM、Google、Chromium等预设风格中选择一个或自定义。# 基于LLVM风格稍作修改 BasedOnStyle: LLVM IndentWidth: 4 TabWidth: 4 UseTab: Never BreakBeforeBraces: Allman ColumnLimit: 100在VSCode中安装Clang-Format扩展并设置保存时自动格式化。也可以在命令行中手动格式化所有文件clang-format -i src/**/*.cpp src/**/*.h include/**/*.hclang-tidy (静态分析)在CMake中启用它# 在CMakeLists.txt中add_executable之后 if(CMAKE_EXPORT_COMPILE_COMMANDS) set(CMAKE_CXX_CLANG_TIDY “clang-tidy;-checks*;-header-filter.”) endif()这会在编译时自动运行clang-tidy进行检查。-checks*启用所有检查可能很严格你可以指定具体的检查项如-checksclang-analyzer-*,performance-*,readability-*。生成compile_commands.json文件clang-tidy需要它cmake -DCMAKE_EXPORT_COMPILE_COMMANDSON ..这会在build目录下生成该文件。手动运行检查clang-tidy -p build src/**/*.cpp -- -stdc17将这些工具集成到你的开发流程如Git提交钩子中能强制保证代码风格统一并发现许多常见bug如未初始化的变量、内存泄漏风险等。5. 从框架出发下一步学什么有了这个稳固的框架作为起点你的C学习之路就可以更专注于语言特性和算法本身而不是反复折腾环境。接下来我建议你按照这个路径深入深入C核心语言在框架里练习。学习智能指针std::unique_ptr,std::shared_ptr来管理内存彻底告别new/delete。掌握移动语义和完美转发理解右值引用。熟悉STL容器和算法vector,map,sort,find这是你日常编码的利器。用框架做小项目参考你提供的那个资源列表0voice/introduce_c-cpp_manual里的“100个一学就会的项目”。比如用这个框架去实现一个“职工工资管理系统”No.41或者一个“基于epoll的高并发聊天室”No.22。把框架的src/core/换成你的业务逻辑在实战中巩固。学习设计模式与架构当你的项目代码超过1000行你会开始遇到“如何组织代码更清晰”的问题。这时可以学习单例模式、工厂模式、观察者模式等并思考如何在你的框架模块中应用。探索专业领域库图形界面用Qt框架替换掉命令行给你的计算器做个窗口。网络编程尝试Boost.Asio或libevent写一个简单的HTTP服务器参考列表中的TinyWebServer。游戏开发用SFML或raylib做一个贪吃蛇或俄罗斯方块。数据处理学习OpenCV做图像处理或用Eigen做矩阵运算。理解底层与性能在框架中尝试编写一些性能敏感的模块学习如何使用Valgrind或AddressSanitizer检测内存错误用perf或gprof分析性能瓶颈。理解缓存友好性、虚函数开销等概念。这个框架的价值在于它为你屏蔽了项目初始的混乱让你能快速进入“编码-构建-测试-运行”的正循环。随着你经验的积累你会不断回头修改和优化这个框架本身——比如引入更复杂的CMake模块、配置CI/CD持续集成、集成性能剖析工具——这个过程本身就是一名C开发者成长的缩影。记住最好的框架不是一成不变的而是那个能随着你的项目一起演进、始终为你提供坚实起点的伙伴。现在就从这个框架开始写下你的第一个“像样”的C程序吧。
返回列表