1. 目的
准备开一个新的系列, cracking c++。是看 https://hackingcpp.com/ 这个网站的相关学习记录。
本文是第一篇,是学习C++中 #include
的用法。这里假定读者知道可以用 -I
参数来告诉 g++/clang++ 搜索路径。
2. 从 Hello World 说起
C++ 的 hello world 程序如下:
#include <iostream>
// our first program
int main ()
{
std::cout << "Hello World\n";
}
本文只考虑第一行代码 #include <iostream>
的理解。
#include
是预处理指令, <iostream>
通常理解为一个名为 iostream
的文件, 并且 iostream
文件能被编译器找到。
3. #include <xx> 和 #include "xx" 的区别?
3.1 相同点:implemention defined
这两种预处理指令用法, 都是编译器实现决定的, 换言之C和C++标准并没有给出明确的预期行为。
而实际使用的C/C++编译器,可以认为都把这两个指令实现为 “包含文件”, 虽然理论上说编译器可以自行定义 “header”, header 不必是文件的形式, 然后包含这个 header。
而对于这两者的区别, 那更是编译器实现所决定的: 可以去翻看各个C/C++编译器的文档,不过其实没啥必要 – 观察现有的流行 C++ 库, 看看他们怎么用的?
更具体说, 对于一个成熟的C++开源项目, 它的实现通常不止一个文件,也不止一层目录结构, 那么它的核心实现中, 包含自己定义的源代码时, 是用 #include <xx/yy.hpp>
还是 #include "xx/yy.hpp"
呢?
4. 观摩流行的C++开源项目:用哪种 include 的都有
4.1 leveldb: #include "xx/yy.h" 流
leveldb 是知名数据库,谷歌开源,Jeaf Dean 代表作
https://github.com/google/leveldb/blob/main/db/db_impl.cc
#include "db/builder.h"
#include "db/db_iter.h"
#include "db/dbformat.h"
#include "db/filename.h"
#include "db/log_reader.h"
#include "db/log_writer.h"
4.2 rocksdb: #include "xx/yy.h" 流
rocksdb 在代码风格上继承了 leveldb
https://github.com/facebook/rocksdb/blob/main/db/column_family.cc
#include "db/blob/blob_file_cache.h"
#include "db/blob/blob_source.h"
#include "db/compaction/compaction_picker.h"
#include "db/compaction/compaction_picker_fifo.h"
4.3 pytorch: #include <xx/yy.hpp> 流
pytorch 是知名的深度学习框架
https://github.com/pytorch/pytorch/blob/main/torch/csrc/tensor/python_tensor.cpp
#include <torch/csrc/tensor/python_tensor.h>
#include <pybind11/pybind11.h>
#include <structmember.h>
#include <torch/csrc/utils/pybind.h>
#include <torch/csrc/Dtype.h>
#include <torch/csrc/DynamicTypes.h>
#include <torch/csrc/Exceptions.h>
#include <torch/csrc/Layout.h>
#include <torch/csrc/autograd/generated/VariableType.h>
#include <ATen/ATen.h>
4.4 googletest: #include "xx/yy.h" 流
googletest 是知名的单元测试框架
https://github.com/google/googletest/blob/main/googletest/src/gtest-death-test.cc
#include "gtest/internal/custom/gtest.h"
#include "gtest/internal/gtest-port.h"
#include "gtest/gtest-message.h"
#include "gtest/internal/gtest-string.h"
#include "src/gtest-internal-inl.h"
4.5 opencv: #include "xx/yy.hpp" 流
opencv 是知名的 计算机视觉库
https://github.com/opencv/opencv/blob/4.x/modules/core/src/buffer_area.cpp
#include "opencv2/core/utils/buffer_area.private.hpp"
#include "opencv2/core/utils/configuration.private.hpp"
4.6 gRPC: #include <xx/yy.h> 和 #include "xx/yy.h" 混用流
https://github.com/grpc/grpc/blob/master/src/core/lib/gpr/alloc.cc
#include <grpc/support/port_platform.h>
#include <stdlib.h>
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include "src/core/lib/gprpp/crash.h"
4.7 llvm-mlir: #include "xx/yy.h" 流
mlir 是 llvm 中的一个模块,可用于深度学习编译器开发
https://github.com/llvm/llvm-project/blob/main/mlir/lib/Dialect/AMDGPU/IR/AMDGPUDialect.cpp
#include "mlir/Dialect/AMDGPU/IR/AMDGPUDialect.h"
#include "mlir/Dialect/Arith/IR/Arith.h"
#include "mlir/Dialect/GPU/IR/GPUDialect.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/Diagnostics.h"
#include "mlir/IR/DialectImplementation.h"
#include "mlir/IR/Matchers.h"
#include "mlir/IR/OpImplementation.h"
#include "mlir/IR/PatternMatch.h"
#include "mlir/IR/TypeUtilities.h"
#include "llvm/ADT/TypeSwitch.h"
4.8 结论
可以看到对于一个文件 xx.h
可以有如下5种包含方式, 都是可以的, C++纯度越高的项目,使用的方式越靠“下方”,不过其实差别不大; 可以直接无脑#include <xx/yy.hpp>
.文章来源:https://www.toymoban.com/news/detail-474228.html
-
#include "xx.h"
// bad, no sub directory as prefix -
#include "xx/yy.h"
// ok. header seems provide C API -
#include <xx/yy.h>
// ditto -
#include "xx/yy.hpp"
// ok. header provides C++ API -
#include <xx/yy.hpp>
// ditto
5. References
https://stackoverflow.com/questions/21593/what-is-the-difference-between-include-filename-and-include-filename?answertab=trending#tab-top文章来源地址https://www.toymoban.com/news/detail-474228.html
到了这里,关于Cracking C++(1): 头文件包含的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!