考虑以下示例。它在标记线处与gcc 5.4进行了段错误
我用g++ -O3 -std=c++11
编译它。它在指令movaps
处失败,我怀疑它执行未对齐的内存访问。可能是gcc为这样一个简单的样本生成非法代码还是我遗漏了什么?
我在Intel i5-5200U上运行它。
#include <vector>
#include <memory>
#include <cstdint>
using namespace std;
__attribute__ ((noinline))
void SerializeTo(const vector<uint64_t>& v, uint8_t* dest) {
for (size_t i = 0; i < v.size(); ++i) {
*reinterpret_cast<uint64_t*>(dest) = v[i]; // Segfaults here.
dest += sizeof(uint64_t);
}
}
int main() {
std::vector<uint64_t> d(64);
unique_ptr<uint8_t[]> tmp(new uint8_t[1024]);
SerializeTo(d, tmp.get() + 6);
return 0;
}
答案 0 :(得分:2)
您将6个字节移入数组,因此它现在不对齐。编译器不能知道它必须避免需要对齐的指令;这就是为什么类型双关语是未定义的行为。
答案 1 :(得分:1)
在c ++中合法执行类型惩罚的方法很少。
魔术函数std::memcpy
是这里的首选工具:
__attribute__ ((noinline))
void SerializeTo(const vector<uint64_t>& v, uint8_t* dest) {
for (size_t i = 0; i < v.size(); ++i) {
std::memcpy(dest, std::addressof(v[i]), sizeof(v[i]));
dest += sizeof(uint64_t);
}
}
结果-std=c++11 -O3 -march=native -Wall -pedantic
SerializeTo(std::vector<unsigned long, std::allocator<unsigned long> > const&, unsigned char*): # @SerializeTo(std::vector<unsigned long, std::allocator<unsigned long> > const&, unsigned char*)
mov rax, qword ptr [rdi]
cmp qword ptr [rdi + 8], rax
je .LBB0_3
xor ecx, ecx
.LBB0_2: # =>This Inner Loop Header: Depth=1
mov rax, qword ptr [rax + 8*rcx]
mov qword ptr [rsi + 8*rcx], rax
add rcx, 1
mov rax, qword ptr [rdi]
mov rdx, qword ptr [rdi + 8]
sub rdx, rax
sar rdx, 3
cmp rcx, rdx
jb .LBB0_2
.LBB0_3:
ret