- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
当我尝试运行使用 g++ 和优化 -O2 构建的程序时,这是一种奇怪的行为。使用:
我有两个成员的结构:
struct A {
uint8_t m8;
Int128 m128;
};
Int128
是:
// #pragma pack(push, 1)
struct Base128 {
__int128_t v{0};
};
// #pragma pack(pop)
#pragma pack(push, 1)
struct Int128: Base128 {
Int128();
};
#pragma pack(pop)
Base128
显式未打包,但 Int128
以对齐 1
打包请注意,Base128
具有显式成员初始化,而 Int128
在另一个翻译单元中具有手动定义的空主体构造函数(以避免内联)。
当我将 Base128
打包更改为与 Int128
相同时,程序不会崩溃。
似乎编译器生成了无效指令:MOVAPS
而不是 MOVUPS
以访问构造函数中的 __int128_t
成员:
00000000000006b0 <_ZN6Int128C1Ev>:
6b0: 66 0f ef c0 pxor %xmm0,%xmm0
6b4: 55 push %rbp
6b5: 48 89 e5 mov %rsp,%rbp
6b8: 0f 29 07 movaps %xmm0,(%rdi)
6bb: 5d pop %rbp
6bc: c3 retq
6bd: 0f 1f 00 nopl (%rax)
反之亦然:
00000000000006b0 <_ZN6Int128C1Ev>:
6b0: 66 0f ef c0 pxor %xmm0,%xmm0
6b4: 55 push %rbp
6b5: 48 89 e5 mov %rsp,%rbp
6b8: 0f 11 07 movups %xmm0,(%rdi)
6bb: 5d pop %rbp
6bc: c3 retq
6bd: 0f 1f 00 nopl (%rax)
你知道我做错了什么吗?
源代码:
测试.h:
#pragma once
#include <cstdint>
//#pragma pack(push, 1) // it fixes problem
struct Base128 {
__int128_t v{0};
};
//#pragma pack(pop)
#pragma pack(push, 1)
struct Int128: Base128 {
Int128();
};
#pragma pack(pop)
struct A {
uint8_t m8;
//Int128 __attribute__((aligned(16))) m128; // it fixes problem
Int128 m128;
};
测试.cpp:
#include "test.h"
// Int128::Int128() : Base128{0} {} // Fixes (why ?!)
Int128::Int128() {}
主要.cpp:
#include "test.h"
int main() {
A a;
return 0;
}
构建和运行:
g++-7 --save-temps -Wall -Wextra -std=c++14 -O2 -g main.cpp test.cpp && ./a.out
Source code on gitlab is here .它可以按如下所示构建和运行:
./build.sh # build and run (crashes)
./build.sh [1..5] # where 1..5 -- different fixes
最佳答案
来自documentation alignas
,据我所知相当于 gcc 的打包属性:
If the strictest (largest) alignas on a declaration is weaker than the alignment it would have without any alignas specifiers (that is, weaker than its natural alignment or weaker than alignas on another declaration of the same object or type), the program is ill-formed:
struct alignas(8) S {};
struct alignas(1) U { S s; }; // error: alignment of U would have been 8 without alignas(1)
此示例实际上与您的示例完全相同(将类的父级视为其第一个成员)。
因此我们可以肯定地说您的程序格式错误,从而调用未定义行为。您的大多数变通办法基本上都可以被忽略,因为基本上只是“运气”。无需解释它们为何起作用。
有趣的是,在代码中交换标准 alignas()
时,gcc 仍然没有报错,但 clang 开始正确报告错误:https://gcc.godbolt.org/z/EEErXg
编辑: alignas()
和 gcc 打包的等价性引用:
GCC 表示它是 MSVC 功能的直接端口:https://gcc.gnu.org/onlinedocs/gcc-4.8.0/gcc/Structure_002dPacking-Pragmas.html
Microsoft 说 alignas()
是同一件事:https://msdn.microsoft.com/en-us/library/2e70t5y1.aspx
关于c++ - 使用 g++7 构建的代码因访问未对齐的内存而崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52894849/
我是一名优秀的程序员,十分优秀!