【问题标题】:check integer constants have different values at compilation time检查整数常量在编译时有不同的值
【发布时间】:2012-08-07 06:23:20
【问题描述】:

我的问题如下。我有大量用作标识符的静态常量整数。出于这个原因,我想知道是否可以在编译时检查是否有多个具有相同值的常量(某种静态断言......)。

我不想使用枚举,因为这些常量是在不同的模块中定义的,我不想让所有的枚举都像一个很长的枚举(其中一些彼此不相关)。

这里有一个基本示例:

// module: foo.h
const uint32_t ELEMENT_TYPE_FOO_X = 46;
const uint32_t ELEMENT_TYPE_FOO_Y = 51;
...

// module: boo.h
const uint32_t ELEMENT_TYPE_BOO_C = 21;
const uint32_t ELEMENT_TYPE_BOO_D = 51;

错误:ELEMENT_TYPE_FOO_Y 和 ELEMENT_TYPE_BOO_D 具有相同的值。

我根本不是专家,我想到的检测此错误的唯一方法是模板专业化。

template<uint32_t N>
struct element_traits {
};

template<ELEMENT_TYPE_FOO_X> {
    enum { value = ELEMENT_TYPE_FOO };
};

但这似乎是一个复杂的解决方案。我不知道是否有更优雅/更好的解决方案。到目前为止我还没有找到任何东西。

提前致谢。

【问题讨论】:

  • 通过代码库进行一次好的老式搜索怎么样?
  • 这些常量是否有任何共同点可以让您处理它们?
  • Luchian Grigore:“搜索代码库”是什么意思?
  • Kerrek SB:除了类型之外,它们没有其他共同点。
  • 你能把uint32_t的类型改成class my_id_type之类的吗?如果是这样,您可能会找到一种使用模板递归的方法。

标签: c++ compilation


【解决方案1】:

您当然可以使用宏来做到这一点:

#define UNIQUE_CONSTANT(variable, value) \
  const uint32_t variable = value; \
  bool constant_val_##value = value;

那么如果同一个值被使用两次就会得到多重定义错误。

(从技术上讲,这将在链接时检测错误,而不是编译时。)

【讨论】:

  • 不错的主意。但是内存消耗会不必要地增加(就像我的解决方案一样)。如果我找不到其他东西,我想我会选择在运行时检查值。
  • 每个常量一个字节似乎并没有那么大的内存占用。如果你的链接器是好的,那些额外的变量永远不会被引用,并且可以从最终的可执行文件中删除。
  • 这看起来不错。如果将第三行替换为struct unique_id_##value {},则应该没有内存占用。您只是在声明一个未使用的空数据结构。
  • 唯一的担心是在不同的命名空间中使用这个宏是行不通的:d
  • 那个值不区分大小写。 0xFFEF != 0xffef != 65519
【解决方案2】:

基于 Keith 的解决方案。我可以“检查”常量对于调试构建具有独特的价值,并在发布构建时跳过它。

#ifdef DEBUG
#define DEFINE_UNIQUE_CONSTANT(variable, value) \
    const uint32_t variable = value;            \
    uint32_t constant_val_##value = value;
#else
#define DEFINE_UNIQUE_CONSTANT(variable, value) \
    const uint32_t variable = value;
#endif

【讨论】:

    【解决方案3】:

    如果大量常量必须不同并且必须在不同的源文件中定义,那么您可以通过这种方式生成它们,例如,从包含文件名和相应常量名的文件开始,并在每次构建时生成其余的。

    输入文件:

    [foo.h]
    ELEMENT_TYPE_FOO_X
    ELEMENT_TYPE_FOO_Y
    
    [boo.h]
    ELEMENT_TYPE_BOO_C
    ELEMENT_TYPE_BOO_D
    

    脚本:

    #!/usr/bin/env python
    from ConfigParser import SafeConfigParser
    from itertools import count
    
    config = SafeConfigParser(allow_no_value=True)
    config.optionxform = lambda x: x # use names as-is
    config.read('input.cfg')
    
    counter = count(1)
    for filename in config.sections():
        with open(filename, 'w') as f:
             for (name, _), i in zip(config.items(filename), counter):
                 f.write("const uint32_t %s = %s;\n" % (name, i))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-09-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-19
      • 2014-02-10
      • 2015-12-04
      相关资源
      最近更新 更多