C++ 完整实践:RAII 宿主连接 POSIX C 库 · C++原生宿主的调用顺序是什么至C++宿主怎样与C实现保持同一源码
先具备 C++ 值语义、异常和 RAII 知识。本专题沿 ABI 契约、拥有关系、完整宿主、排错推进。示例未执行,仅完成静态文本/模板检查,不声称运行通过。
专题入口:C++ C ABI 边界:链接、不透明句柄与错误值 · C++ 原生资源所有权:接管、析构与借用 · C++ 完整实践:RAII 宿主连接 POSIX C 库 · C++ 原生边界排错:符号、释放器与异常政策
C++ 完整实践:RAII 宿主连接 POSIX C 库
先具备 C++ 值语义、异常和 RAII 知识。本专题沿 ABI 契约、拥有关系、完整宿主、排错推进。示例未执行,仅完成静态文本/模板检查,不声称运行通过。
专题入口:C++ C ABI 边界:链接、不透明句柄与错误值 · C++ 原生资源所有权:接管、析构与借用 · C++ 完整实践:RAII 宿主连接 POSIX C 库 · C++ 原生边界排错:符号、释放器与异常政策
C++原生宿主的调用顺序是什么
C++原生宿主的调用顺序是什么:宿主按 create → RAII接管 → run → report 的顺序执行。create 复制两条路径,run 完成线程收拢,report 才写借用的 stdout;异常统一在 main 捕获并返回1。参数不足返回2,成功返回0。
输入 abc LF 与 de LF 预期总和7;这验证两个 C worker 的结果确实经 C ABI 返回并由宿主发出,而不是 C++ 重写一套计数。示例未执行,输出是规格;不能据此声称线程调度、链接或某平台行为已验证。
C++宿主怎样与C实现保持同一源码
C++宿主怎样与C实现保持同一源码:main.cpp 只包含 scan.h 并调用公共函数,scan.c 实现私有结构。下面与 C 实践页引用完全相同的项目文件;两条学习路线共享一份程序,避免改了 C 版本却遗漏 C++ 宿主版本。
CMake 明确启用 C 和 CXX 两种语言,不能把所有 .c 改由 C++ 编译来掩盖头文件问题。静态库的公共头目录与 Threads::Threads 依赖传播给宿主;本例不引入动态加载、导出宏或插件搜索路径。
CMakeLists.txt(同源文件,示例未执行)
cmake_minimum_required(VERSION 3.20)
project(byte_scan LANGUAGES C CXX)
if(NOT UNIX)
message(FATAL_ERROR "POSIX only: use Linux, macOS, or a Linux environment in WSL")
endif()
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
find_package(Threads REQUIRED)
add_library(byte_scan STATIC scan.c)
target_include_directories(byte_scan PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_compile_definitions(byte_scan PRIVATE _POSIX_C_SOURCE=200809L)
target_compile_options(byte_scan PRIVATE -Wall -Wextra -Wpedantic)
target_link_libraries(byte_scan PUBLIC Threads::Threads)
add_executable(byte-report main.cpp)
target_link_libraries(byte-report PRIVATE byte_scan)
target_compile_definitions(byte-report PRIVATE _POSIX_C_SOURCE=200809L)
target_compile_options(byte-report PRIVATE -Wall -Wextra -Wpedantic)
include(CTest)
if(BUILD_TESTING)
add_executable(scan-contract-test test_scan.c)
target_link_libraries(scan-contract-test PRIVATE byte_scan)
target_compile_options(scan-contract-test PRIVATE -Wall -Wextra -Wpedantic)
add_test(NAME scan-contract COMMAND scan-contract-test
${CMAKE_CURRENT_SOURCE_DIR}/inputs/left.txt
${CMAKE_CURRENT_SOURCE_DIR}/inputs/right.txt)
endif()ENVIRONMENT.md(同源文件,示例未执行)
# 依赖、环境与平台边界
示例未执行。C11、C++20、POSIX.1-2008接口、CMake >=3.20。
第三方依赖:无;pthread 来自目标平台线程库,由 Threads::Threads 表达。
_POSIX_C_SOURCE=200809L 在库目标定义,用于声明 strdup 等 POSIX 接口。
macOS SDK 是否接受全部选项/宏尚未实测;不宣称原生 macOS 验收。
Linux 发行版、libc、CPU 架构、C/C++编译器版本尚未选择并实测。
Windows 原生不适用;WSL 仅表示 Linux 环境路径,没有执行 WSL 验证。
当前进程不能被取消,也不能在 run 时 fork 后继续操作本句柄。
可信输入、稳定有限普通文件、单一外部调用线程是前提。
Linux close 报错时通常已释放描述符,不盲目重试;POSIX.1-2008 对
close/EINTR 后资源状态不作统一保证,本例可能在其他实现上遗留描述符。
因此跨平台不承诺 EINTR 关闭路径绝无泄漏。macOS 仅理论说明,无特定行为实测。
示例不实现 signal/cancellation 安全的通用资源层,不适合直接复制为生产SDK。
后续读者自行验证时记录:OS/架构、libc或SDK、C/C++编译器、CMake版本、
Shell、输入换行、构建日志、stdout/stderr/退出码、测试及诊断工具结果。inputs/left.txt(同源文件,示例未执行)
abcinputs/right.txt(同源文件,示例未执行)
demain.cpp(同源文件,示例未执行)
#include "scan.h"
#include <csignal>
#include <exception>
#include <iostream>
#include <memory>
#include <system_error>
#include <unistd.h>
struct ScanDeleter {
void operator()(scan *s) const noexcept { scan_destroy(s); }
};
using ScanOwner = std::unique_ptr<scan, ScanDeleter>;
static void check(int code, const char *operation) {
if (code != 0)
throw std::system_error(code, std::generic_category(), operation);
}
int main(int argc, char **argv) {
if (argc != 3) {
std::cerr << "usage: byte-report LEFT RIGHT\n";
return 2;
}
// CLI policy only: let write return EPIPE instead of signal termination.
if (std::signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
std::cerr << "cannot set SIGPIPE policy\n";
return 1;
}
try {
scan *raw = nullptr;
check(scan_create(argv[1], argv[2], &raw), "create");
ScanOwner owner(raw);
check(scan_run(owner.get()), "run");
check(scan_report(owner.get(), STDOUT_FILENO), "report");
return 0;
} catch (const std::exception &e) {
std::cerr << e.what() << '\n';
return 1;
}
}README.md(同源文件,示例未执行)
# POSIX 字节扫描与 C++ RAII 宿主
示例未执行;未编译、未配置 CMake、未运行测试。所有结果是预期。
依赖:C11、C++20、POSIX.1-2008 的文件与 pthread API、CMake >=3.20。
不依赖第三方库,不安装依赖。目标为 Linux / macOS 的 POSIX 环境;
Windows 只能在 WSL 的 Linux 环境阅读和尝试,非 Windows 原生项目。
这些是教学要求,未固定或验证具体发行版、SDK、编译器版本组合。
静态库同工具链同架构构建;不承诺不同编译器/运行库/位数之间二进制兼容。
仓库根目录 Bash/Zsh 命令(仅供读者自行尝试,本轮未执行):
```sh
cmake -S examples/native/p2-posix-cpp -B build/native-p2
cmake --build build/native-p2
./build/native-p2/byte-report examples/native/p2-posix-cpp/inputs/left.txt examples/native/p2-posix-cpp/inputs/right.txt
ctest --test-dir build/native-p2 --output-on-failure
```
预期标准输出 `bytes=7` 后一个 LF,退出0。输入文件必须保持 LF,
left.txt 为4字节、right.txt 为3字节;CRLF 会改变字节数。
两个工作线程各自打开一个普通文件、循环读取,在同一互斥锁下提交字节数。
主线程 join 所有已创建线程,成功后才允许 report。
路径复制给库,C++ unique_ptr 用库的销毁函数回收。
只接收可信路径与有限、执行时不变的普通文件;不保证打开设备的安全性,
不提供文件快照、取消、超时、递归目录扫描或恶意输入隔离。
O_NONBLOCK 避免 FIFO 的常规等待,但不是对任意设备的安全策略。
两个输入为同一路径时会计算两遍;这是两个输入项的和,不是去重扫描。
stdout 借用不关闭;CLI 忽略 SIGPIPE 使管道关闭成为 EPIPE 错误。
report 写失败可能已有前缀输出,不能回滚。stderr 文案依系统不同。
详细失败和手工推演见 TEST-SPEC.md;不把预期当作实测。
test_scan.c 是完整但未编译、未执行的基础 API 测试驱动,CTest 预期输出
scan contracts passed 并成功退出;包含状态拒绝、重复输入、缺失路径、无效输出描述符。
TEST-SPEC 的系统调用替身故障注入尚未实现,不能声称基础测试已覆盖它们。继续阅读
- 知识专题
- 排错
- 知识专题