为什么应该使用模块(Module)替代头文件(Header)?
头文件糟透了!
众所周知,C程序在编译时一般会预处理头文件:
常规解决办法如下:
- LLVM_WHY_PREFIX_UPPER_MACROS
- LLVM_CLANG_INCLUDE_GUARD_H
- template<class_Tp>
- const_Tp&min(const_Tp&__a,
- const_Tp&__b);
- #include<windows.h>
- #undefmin//because#defineNOMINMAX
- #undefmax//doesn’t
但结果依然不够理想,比较一下代码与程序大小你会发现:
另外,头文件形式的可扩展性天生不足。假设有n个源文件,每个源文件引用了m个头文件,那么构建过程的开销会是m×n。这在C++中表现得尤为糟糕。所以预说处理头文件是一个非常糟糕的解决方案。
C家族的模块系统
模块是什么?
使用“import”导入已命名的模块:
import会在源文件中忽略预处理状态,并且选择性导入,所以弹性(resilience)非常好。
使用“import”会导入什么?
- 函数、变量、类型、模板、宏,等等;
- 公开API——其它的都隐藏;
- 没有特别的命名空间机制。
C/C++引入模块会怎么样?
引入模块的目标在于:
- 在源文件中指定模块名称;
- API公开;
- 没有头文件!
要编写一个模块非常简单,只需要使用export:
但是这么做会遇到很多遗留问题:
- 需要迁移现在基于头文件的类库;
- 与不支持模块的编译器的互操作性;
- 工具需要理解模块;
所以应该使用引入模块的过渡方案——直接从头文件中构建模块。这么做有以下好处:
- 头文件有利于互操作;
- 程序员不需要完全改变自己习惯的开发模式;
模块地图(Module Map)
模块地图是模块的关键,用来定位模块相关(子)模块,包含以下功能:
-
模块定义命名(子)模块
- 头文件在(子)模块中包含命名头文件的内容
保护伞头文件(Umbrella Header)
模块编译过程:
- 找到命名模块的module map;
- 产生一个独立编译器实例;
- 在module map中解析头文件。
编辑模块文件过程:
- 在“import”声明处导入模块文件;
- 把模块文件保存在缓存中待重用。
从头文件到模块化
从头文件编程转换到使用模块非常简单:
库方面:合并复合定义的结构、函数、宏,并且为头文件导入依赖,最后编写好模块地图;
开发者方面只需要从“#include”过渡到“import”:
- 把“#inlude”都换成“import”;
- 使用module maps确定(子)模块(类似头文件里的“#include”);
当然,你也可以使用工具来自动化重写代码,非常简单。
工具
编辑性能
使用模块能够提升语法解析性能:
- 模块化的头文件只需要解析一次,之后放在缓存中,于是m×n --> m+n
- 所有基于源(source-based)工具都能带来好处
-
自动链接大大简化了库的使用
-
自动导入可以阻止“#include”带来的可怕的调试结果
调试流
通过DWARF的双程调试有损耗:
另外调试过程还会出现信息冗余
那使用模块的调试又会怎样?
1.提高了构建性能
- 编译器发出的DWARF更少
- 链接器清除重复的DWARF也更少
2.提高了调试体验
- 调试器的ASF精度非常完美
- 调试器不需要寻找DWARF
总结
总而言之,C/C++使用模块化非常有潜力:
- 编译/构建时间的缩短
- 修复各种预处理问题
- 更好的工具体验
- 通过设计,能够平稳地过渡
- Clang实现已经在进行了
这个Slide在Hacker News上引起了激烈讨论,大部分网友还是赞成模块化的方式:
baberman:对我来说没什么不便,而且还给出了过渡方案,可能会很适合某些C/C++项目。我们应该对任何提升C/C++性能的想法持开放态度。
greggman:预处理有什么不好吗?如果我不想用预处理,我完全可以使用Objective-C等。现在的机器性能已经够强大了,import在编译上的性能优势对我来说没有任何吸引力,我更喜欢C/C++的传统方式。
msbarnett反驳greggman:我认为这正是这份提议的精髓所在,你既可以保留使用#include,也可以从现在开始就转向import模块的方式。
_djo_:这个想法会非常有前途!要说缺点的话就是来得太迟了!
nkurz:我不同意“m个头文件+n个源文件 --> m×n倍编译性能”。只要使用“#ifndef _HEADER_H”就不会出现这个问题,或者,为什么不使用#include_once <header.h>来解决呢?预处理很可怕吗?预处理确实有一些问题,但是却是可以克服的。
SeoxyS:我不关心性能,现在性能已经不是问题了,我更关心怎样给开发者更少的负担。
各位CSDN网友是怎样看的呢?欢迎一起讨论。
相关链接:Doug的Slide、Hacker News上的讨论
相关推荐
3. **头文件的引用方式**:在C/C++中,头文件的引用方式有两种,一种是使用尖括号`<>`,另一种是使用双引号`""`。尖括号通常用于引用系统库中的头文件,而双引号则用于引用用户自定义的头文件。然而,有些程序员在...
在这个名为"openssl-include.rar"的压缩包中,包含了C语言编程时使用OpenSSL所需的头文件,这对于在Visual C++环境下开发相关项目尤其有用。下面,我们将深入探讨这些知识点。 首先,`openssl_ssl`是指OpenSSL中的...
C++20 模块是该编程语言的一个重要更新,为开发者带来了许多优势。模块的主要目的是提高代码的可重用性和隔离性,减少命名冲突,同时通过预处理优化编译时间。在 C++20 之前,头文件是组织和共享代码的主要方式,但...
C&C++语言是计算机编程领域中的基础且强大的工具,它们为开发者提供了低级内存管理和高性能编程的能力。"C&C++语言参考"是一个重要的资源,它涵盖了C和C++语言的各个方面,包括标准库、预处理命令和操作符优先级等...
4. **编译C/C++代码为动态链接库**:使用编译器(如GCC)将C/C++代码编译成.so库文件,并确保这些库文件被正确加载到Android运行时环境中。 5. **集成与测试**:将生成的动态链接库文件放置到指定目录下,并在Java...
在C++和C编程中,程序通常被划分为两类文件:**头文件**和**定义文件**。 - **头文件**:主要用于保存程序的声明(如函数原型、类定义等)。C++/C的头文件后缀一般为`.h`。 - **定义文件**:主要包含具体的实现细节...
本篇将深入探讨如何使用C/C++语言开发一个针对SATA硬盘的驱动程序,特别是在嵌入式操作系统VxWorks中的实现。 首先,我们来了解一下什么是ATA(Advanced Technology Attachment)协议。ATA是一种广泛应用于硬盘、...
这意味着可以在Objective-C程序中直接使用C的库和函数,这为开发提供了极大的灵活性。 #### 3.4 新类型与值 Objective-C引入了新的数据类型和值,包括: - `BOOL`: 布尔类型,可以是`YES`或`NO`。 - `nil`: 表示空...
C++的预处理器与C基本相同,但C++中`#include`可以使用尖括号(`<iostream>`)和引号(`"iostream"`)两种方式,尖括号通常用于标准库,引号用于本地头文件。 总的来说,C++在保留C语言的效率和灵活性的同时,增强...
在C++中,通常使用标准库中的`<sys/socket.h>`和`<netinet/in.h>`等头文件来处理套接字操作。 再者,"C++"作为主要的编程语言,意味着源码将使用面向对象的编程思想。C++提供了类、对象、封装、继承、多态等特性,...
2. **生成头文件**:使用`javah`工具(在现代版本的Android Studio中,已经由`javac -h`取代)从包含native方法的Java类生成C/C++头文件。这个头文件包含了Java方法签名的C/C++声明。 3. **编写本地代码**:基于...
总的来说,Visual C++中调用DLL实现数据加密涉及到模块化编程、动态链接技术、加密算法以及Windows API的使用。开发者需要具备扎实的C++基础知识,对Windows编程有深入理解,并熟悉各种加密算法的原理,才能有效地...
头文件在C或C++编程中用于包含常量定义、函数声明、结构体定义等,帮助程序员在多个源文件之间共享信息。在ARM开发中,头文件可能包括芯片厂商提供的外设驱动接口、系统配置宏、中断向量定义等。 3. **library** ...
标题 "C++小程序" 暗示我们关注的是使用C++编程语言开发的微型应用程序。C++是一种强大的、面向对象的编程语言,广泛应用于系统软件、应用软件、游戏开发、设备驱动程序等领域。在这个场景中,提到的是用VC++6.0...
4. **VC 6.0**:Visual C++ 6.0是微软发布的一个早期版本的集成开发环境(IDE),虽然现在已经被更新的版本取代,但在某些特定领域,如教学和老项目的维护,它仍然被广泛使用。 5. **源代码文件**: - **Connected...
7. **代码库和头文件**:Turbo C++ 3.0自带了一系列标准库函数和头文件,包括I/O操作、数学运算、字符串处理等,方便开发者快速构建应用程序。 8. **图形编程**:尽管运行在DOS下,Turbo C++ 3.0仍然支持图形编程,...
Objective-C是苹果生态系统中用于开发iOS和macOS应用的主要编程语言,它基于C语言,并添加了面向对象的特性。在初学者看来,Objective-C的语法可能显得复杂,特别是它的消息传递机制和类定义方式,但理解了其核心...
- 在项目目录下的`app`模块的`build.gradle`文件中,启用C++支持。添加以下代码: ```groovy android { ... externalNativeBuild { cmake { cppFlags "" abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', '...