Могу ли я указать целочисленную константу в байтах?

Я использую C ++ 11 в моем проекте, и мне было интересно, как лучше представить магическое число ELF. Я не фанат шестнадцатеричных литералов, поэтому я искал что-то лучшее, чем:

const uint32 ELF_MAGIC_NUMBER = 0x7F454c46; // 0x7F, E, L, F

Итак, я попытался написать:

const uint32 ELF_MAGIC_NUMBER = { 0x7F, 'E', 'L', 'F' };

но компилятор жалуется, что в списке инициализатора слишком много элементов, что понятно, хотя и раздражает.

Есть ли способ написать целочисленный литерал в терминах его байтов? Я чувствую, что первый вариант, хотя он работает, не так удобен для чтения во втором.

17

Решение

Так как вы можете позволить себе C ++ 11, вы можете просто определить немного constexpr помощник, который позволил бы оценить время компиляции:

#include <cstdint>

constexpr std::uint32_t from_bytes(char b1, char b2, char b3, char b4)
{
return b4 +
(static_cast<std::uint32_t>(b3) << 8) +
(static_cast<std::uint32_t>(b2) << 16) +
(static_cast<std::uint32_t>(b1) << 24);
}

Таким образом, ваш код не будет сильно отличаться от оригинальной версии:

const std::uint32_t ELF_MAGIC_NUMBER = from_bytes(0x7F, 'E', 'L', 'F');

int main()
{
static_assert(ELF_MAGIC_NUMBER == 0x7F454c46, "!");
}

Вот живой пример.

18

Другие решения

У многих компиляторов есть эта малоизвестная особенность: многозначные литералы символов.

uint32 ELF_MAGIC_NUMBER = '\177ELF';

Боюсь, вам придется использовать восьмеричные числа для не-символа.

Ах, почти забыл! Смысл этого зависит от компилятора, поэтому я бы не стал этого делать.

Но если вы можете использовать C ++ 11, вы можете использовать constexpr и пользовательские литералы:

constexpr uint32_t operator "" _mc (const char *str, size_t len)
{
return len==4?
(str[0] << 24) | (str[1] << 16) | (str[2] << 8) | str[3] :
throw "_mc literal must be of length 4";
}

constexpr uint32_t ELF_MAGIC_NUMBER = "\177ELF"_mc;

Это имеет приятную особенность, что вы можете использовать конкатенацию строк для использования шестнадцатеричных символов:

constexpr uint32_t ELF_MAGIC_NUMBER = "\x7F""ELF"_mc;
9

Как насчет:

const uint32 i = 0x1000000 * 0x7F
+ 0x10000 * 'E'
+ 0x100 * 'L'
+ 0x1 * 'F';

Потенциально более читабельно (вопрос мнения):

const uint32 i = 0x01000000 * 0x7F
+ 0x00010000 * 'E'
+ 0x00000100 * 'L'
+ 0x00000001 * 'F';

Редактировать: Я бы исправил свой собственный ответ, сказав, что даже если вы воспользуетесь таким подходом, вы, вероятно, захотите включить шестнадцатеричную версию литерала в свой код в качестве комментария для людей, например. в поисках магического числа в шестнадцатеричном виде или в другом месте. Имея это в виду, поскольку, вероятно, в любом случае лучше иметь там шестнадцатеричную версию, может быть лучше, как другие сказали, определить число в его шестнадцатеричной форме и добавить комментарий относительно того, что оно представляет, то есть использовать ваш оригинал. версия.

4

Делая ту же задачу по-старому с использованием метапрограммирование шаблона

идиома метафункции

template <char a,char b,char c , char d>
struct  MAGIC_NUMBER {
enum { value =d +
(static_cast<uint32_t>(c) << 8) +
(static_cast<uint32_t>(b) << 16) +
(static_cast<uint32_t>(a) << 24)  };
};/*
* usage
*/
const  uint32_t ELF_MAGIC_NUMBER = MAGIC_NUMBER<0x7F, 'E', 'L', 'F'>::value;
4

Ну, это решение, использующее пользовательские литералы, настолько уродливо, что я мог бы заплакать:

#include <string>
#include <sstream>
#include <cstdint>
#include <cstddef>
#include <cassert>

uint32_t operator"" _u32s(const char* str, std::size_t size)
{
std::istringstream ss(std::string(str, size));
std::string token;
int shift = 24;
uint32_t result = 0;
while (std::getline(ss, token, ',') && shift >= 0) {
int value = 0;
if (token.substr(0,2) == "0x") {
std::stringstream hexss;
hexss << std::hex << token;
hexss >> value;
} else if (token.length() == 1) {
value = token[0];
}
result |= (value << shift);
shift -= 8;
}
return result;
}

int main() {
assert("0x7F,E,L,F"_u32s == 0x7F454c46);
}

По сути, теперь вы можете использовать буквальное "0x7F,E,L,F"_u32s, Очевидно, что это далеко не так хорошо, как использование решения во время компиляции, но это интересный эксперимент.

3
По вопросам рекламы [email protected]