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