Cracking C++(1): 头文件包含

文章目录

    • 1. 目的
    • 2. 从 Hello World 说起
    • 3. `#include ` 和 `#include "xx"` 的区别?
      • 3.1 相同点:implemention defined
    • 4. 观摩流行的C++开源项目:用哪种 include 的都有
      • 4.1 leveldb: `#include "xx/yy.h"` 流
      • 4.2 rocksdb: `#include "xx/yy.h"` 流
      • 4.3 pytorch: `#include ` 流
      • 4.4 googletest: `#include "xx/yy.h"` 流
      • 4.5 opencv: `#include "xx/yy.hpp"` 流
      • 4.6 gRPC: `#include ` 和 `#include "xx/yy.h"` 混用流
      • 4.7 llvm-mlir: `#include "xx/yy.h"` 流
      • 4.8 结论
    • 5. References

1. 目的

准备开一个新的系列, cracking c++。是看 https://hackingcpp.com/ 这个网站的相关学习记录。

本文是第一篇,是学习C++中 #include 的用法。这里假定读者知道可以用 -I 参数来告诉 g++/clang++ 搜索路径。

2. 从 Hello World 说起

C++ 的 hello world 程序如下:

#include 
// our first program
int main ()
{
    std::cout << "Hello World\n";
}

本文只考虑第一行代码 #include 的理解。

#include 是预处理指令, 通常理解为一个名为 iostream 的文件, 并且 iostream 文件能被编译器找到。

3. #include #include "xx" 的区别?

3.1 相同点:implemention defined

这两种预处理指令用法, 都是编译器实现决定的, 换言之C和C++标准并没有给出明确的预期行为。

而实际使用的C/C++编译器,可以认为都把这两个指令实现为 “包含文件”, 虽然理论上说编译器可以自行定义 “header”, header 不必是文件的形式, 然后包含这个 header。

而对于这两者的区别, 那更是编译器实现所决定的: 可以去翻看各个C/C++编译器的文档,不过其实没啥必要 – 观察现有的流行 C++ 库, 看看他们怎么用的?

更具体说, 对于一个成熟的C++开源项目, 它的实现通常不止一个文件,也不止一层目录结构, 那么它的核心实现中, 包含自己定义的源代码时, 是用 #include 还是 #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

pytorch 是知名的深度学习框架

https://github.com/pytorch/pytorch/blob/main/torch/csrc/tensor/python_tensor.cpp

#include 

#include 
#include 
#include 

#include 
#include 
#include 
#include 
#include 

#include 

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 #include "xx/yy.h" 混用流

https://github.com/grpc/grpc/blob/master/src/core/lib/gpr/alloc.cc

#include 

#include 
#include 

#include 
#include 

#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 .

  • #include "xx.h" // bad, no sub directory as prefix
  • #include "xx/yy.h" // ok. header seems provide C API
  • #include // ditto
  • #include "xx/yy.hpp" // ok. header provides C++ API
  • #include // ditto

5. References

https://stackoverflow.com/questions/21593/what-is-the-difference-between-include-filename-and-include-filename?answertab=trending#tab-top

你可能感兴趣的:(C/C++,c++,开发语言)