背景
有一个复杂的系统,其中包含多个库和应用程序,几乎每个项目都依赖于定义枚举的头文件(例如foo.h)(#include在几个cpp文件中).设计远非理想(但通常它是遗留系统).
可悲的是,foo.h经常发生变化.
条件
假设我们可以保证foo.h将被更新:只在最后添加元素,而不删除现有值或重新定义它们.
问题
这种修改是否需要重新编译包含头文件的所有代码?我知道这是类的常见问题(通常删除未使用的变量会更改内存布局并最终导致核心转储).我怀疑这也可能与枚举类似,在正常情况下我肯定会重新编译所有内容.目前的情况在所有代码库中引入了一种刚性,这极大地影响了系统的发展方式.
我想知道我是否"必须"重新编译.此信息可用于设置重构策略.
注意
我看过这个问题,但我认为它实际上并没有回答我的问题.
默认答案是:如果翻译单元(=预处理的源文件)的内容发生更改,则必须重新编译它以使其目标文件与其源格式保持同步。
头文件#included的更改会导致翻译单元的预处理源发生更改,因此必须重新编译它以使其完全同步。因此,从这个角度来看,头文件的更改需要重新编译。
但是,这是最保守的方法。(如果任何棘手的方法出了什么问题,您都应该退而求其次)。实际上,如果您所做的只是将枚举数添加到枚举中,则可能不需要重新编译。
如果您e42在标头中引入新的枚举器,但实际上未在文件中的任何位置使用它x.cpp,则很有可能由x.cpp带有e42define的对象生成的对象文件与x.cpp没有带e42定义的对象文件完全相同。因此,从这个角度来看,重新编译是没有意义的。理想情况下,如果生成的目标文件与更改前的文件不同,则只希望重新编译源文件。
假设您没有在文件中使用新的枚举器,那么可以强制更改目标文件的唯一的事情就是:枚举类型的大小可以更改。如果最大的枚举器值为2147483647,并且添加了一个新的枚举器,则枚举本身的大小很有可能将从32位跃升至64位。
您可以通过使用C ++ 11显式指定枚举的基础类型的能力来解决此限制。确保为要扩展的枚举指定它。
enum EnumerationBeingExtended : int
// ^^^^^ this part
{
// ... list of enumerators as before
};
Run Code Online (Sandbox Code Playgroud)
如果您像这样固定了枚举大小(实际上是整个基础类型),则只包含旧定义的枚举的目标文件(不带的那个)很有可能与包含新枚举的e42对象文件(一个与e42)。
当然,从技术上讲,您将处于格式错误的程序区域,因为该程序将违反“一个定义规则”(不同的翻译单位对该枚举的定义不同)。但是,如果您只使用枚举值,那么在实践中您将很安全。
如果您做一些时髦的事情(例如typeid在枚举类型上使用),我将对此技巧保持警惕。但是,如果您仅使用枚举数并且枚举类型本身是“正常”的,那么您应该很好。
当然,理想情况下,您应该将此枚举隔离到仅包含该枚举的头文件中,并大量记录其预期用途。您可能还必须在构建系统中实际留出一些余地,以免由于头文件的更改而无法重建文件。
总结:正式而言,您将有一个格式错误的程序。但实际上,您应该是安全的。