У меня проблема с непереносимым кодом, который работает так, как задумано на компиляторе ARM RealView, но VC ++, GCC отказываются его компилировать, а QAC ++ (инструмент статического анализа) выдает предупреждение.
У меня есть система, которая должна анализировать мнемонические идентификаторы в сообщениях. Мнемоника — это все трехсимвольные 8-битные строки ASCII. Чтобы упростить и оптимизировать синтаксический анализ, а не выполнять сравнение строк с мнемонической строкой, я упаковываю строку в 32-разрядное целое число и выполняю целочисленное сравнение.
Далее, чтобы иметь возможность использовать переключатель / регистр, а не цепочку 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 должна быть константой времени компиляции, но, очевидно, это не так для всех компиляторов. Код является непереносимым, и я предполагаю, что он не определен, или поведение, определяемое реализацией, или просто неправильно!
Очевидные портативные решения имеют недостатки эффективности и ремонтопригодности, поэтому у меня есть два вопроса:
Почему этот код не переносим — что делает макрос не постоянным во время компиляции в некоторых компиляторах?
Есть ли переносимое решение для генерации желаемой постоянной времени компиляции из мнемонической строки?
С 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]);
}
Здесь он прекрасно компилируется с 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]);
}