我需要尽可能快地完成数百万次。假设我有两个包含几个短char
数组的列表:
"a b ", "a c ", "a x ", etc...
" w z", " w y", " q b"
现在我想要从每个列表中形成一个组合。例如,"a b "
和" w z"
将成为"awbz"
。
似乎最有效的方法是将它们存储为32位序列:
"a b " --> 0x00620061
" w z" --> 0x7A007700
现在OR
他们一起得到
0x7A627761 --> "awbz"
我的第一个想法是使用联合,但我知道这在技术上会呈现未定义的行为...写入union变量的一部分,然后从union中读取不同的类型。
union {
unsigned char[4] c;
unsigned int i;
};
我的第二个想法是使用强制转换在int和char []之间切换。有没有办法安全地这样做?
答案 0 :(得分:2)
好消息是,在C11中,读取工会成员而不是最后写入的工会成员并不是未定义的行为。脚注95至6.5.2.3说
如果用于读取union对象内容的成员与上次用于在对象中存储值的成员不同,则该值的对象表示的相应部分将被重新解释为对象表示形式。 6.2.6中描述的新类型(有时称为''punning''的过程)。这可能是陷阱表示。
坏消息是C11编译器仍然很少见。但是,大多数编译器都按预期运行,而gcc长期以来一直保证这种行为。除非有非常强烈的理由不这样做,否则我会使用联盟。
答案 1 :(得分:2)
在C ++中,始终允许向char*
输入punning。所以你很幸运。
只需使用int32_t
按照您的建议存储值。将按位OR的结果存储在变量中,并在其地址上使用reinterpret_cast
。
int32_t first = 0x00620061;
int32_t second = 0x7A007700;
int32_t combined = first | second;
std::string s(reinterpret_cast<const char*>(&combined), 4);
答案 2 :(得分:0)
在某些C / C ++规范中是否为UB,现实是使用union
可能会在几乎所有编译器中按预期工作,例如:
union Char4Int32
{
unsigned char[4] c;
unsigned int32_t i;
};
Char4Int32 first, second, combined;
strncpy(first.c, "a b ", 4);
strncpy(second.c, " w z", 4);
combined.i = first.i | second.i;
std::string s(combined.c, 4);