我在我的一个项目中使用C ++ 11,并且想知道如何最好地表示ELF幻数。我不是十六进制文字的粉丝,所以我一直在寻找比以下更好的东西:
const uint32 ELF_MAGIC_NUMBER = 0x7F454c46; // 0x7F, E, L, F
所以,我试着写:
const uint32 ELF_MAGIC_NUMBER = { 0x7F, 'E', 'L', 'F' };
但编译器抱怨初始化列表中的项目太多,这是可以理解的,虽然很烦人。
有没有办法按字节写一个整数文字?我觉得第一个选项虽然有效,但在第二个选项上并不可读。
答案 0 :(得分:18)
既然您可以负担得起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, "!");
}
这是live example。
答案 1 :(得分:9)
许多编译器都有这个鲜为人知的特性:多字符字符文字。
uint32 ELF_MAGIC_NUMBER = '\177ELF';
你不得不使用八进制数字作为非char,我很害怕。
啊,差点忘了!这意味着编译器依赖,所以我不会这样做。但是如果你可以使用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;
答案 2 :(得分:4)
怎么样:
const uint32 i = 0x1000000 * 0x7F
+ 0x10000 * 'E'
+ 0x100 * 'L'
+ 0x1 * 'F';
潜在的可读性(意见问题):
const uint32 i = 0x01000000 * 0x7F
+ 0x00010000 * 'E'
+ 0x00000100 * 'L'
+ 0x00000001 * 'F';
编辑:我会修改自己的答案,即使你采取这样的方法,你可能希望在你的代码中包含文字的十六进制版本作为注释,为了人们,例如以十六进制形式搜索幻数,或在其他地方查看。考虑到这一点,因为无论如何最好在那里使用十六进制版本,它可能是最好的,因为其他人已经说过以十六进制形式定义数字并添加关于它代表什么的注释,即使用你的原始版本
答案 3 :(得分: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 :(得分:3)
这个解决方案,使用用户定义的文字,是如此丑陋,我可能会哭:
#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
。显然它远不如使用编译时解决方案那么好,但这是一个有趣的实验。