6

我对在 ARM RealView 编译器上按预期工作的不可移植代码有疑问,但 VC++、GCC 拒绝编译它并且 QAC++(一种静态分析工具)发出警告。

问题

我有一个系统需要解析消息中的助记符标识符。助记符都是三个字符的 8 位 ASCII 字符串。为了简化和优化解析而不是对助记字符串执行字符串比较,我将字符串打包成一个 32 位整数并执行整数比较。

此外,为了能够使用 switch/case 而不是 if-elseif 链,我有一个宏,它采用文字字符串并生成关联的整数,在 ARM RealView 中是编译时间常数,但在 GCC x86/ 中没有Linux 或 VC++/Windows:

// Note:  Do not change C cast to static_cast because compiler complains when used in switch/case
#define CONST_MNEMONIC( mn ) ((uint32_t)(((#mn)[2]<<16)|((#mn)[1]<<8)|((#mn)[0])))

然后将其用于 ARM 目标代码,如下所示:

switch( packed_mnemonic )
{
    case CONST_MNEMONIC(RST) :
        ...
        break ;

    case CONST_MNEMONIC(SSD) :
        ...
        break ;

    case CONST_MNEMONIC(DEL) :
        ...
        break ;

    default:
        ...
        break ;
}

case 标签当然必须是编译时常量,但显然并非所有编译器都是如此。该代码是不可移植的,我猜是未定义的或实现定义的行为,或者完全错误!

问题

显而易见的可移植解决方案存在效率和可维护性的缺点,所以我有两个问题:

  1. 为什么这段代码不可移植 - 是什么让宏在某些编译器中不是编译时常量?

  2. 是否有可移植的解决方案从助记符字符串生成所需的编译时间常数?

4

2 回答 2

5

使用 C++11,您可以使用一个constexpr函数:

constexpr int CONST_MNEMONIC(const char* s)
{
    return (static_cast<int>(s[2]) << 16) +
           (static_cast<int>(s[1]) <<  8) +
            static_cast<int>(s[0]);
}
于 2014-01-17T12:52:50.130 回答
3

它在这里用 gcc 4.8 和 clang 3.4 编译得很好......

在 C++11 中,您可以使用:

constexpr uint32_t CONST_MNEMONIC(const char (&s)[4])
{
    return (uint32_t(s[2]) << 16) | (uint32_t(s[1]) << 8) | uint32_t(s[0]);
}
于 2014-01-17T13:05:55.973 回答