在C中,编译器将按照声明它们的顺序布置结构的成员,在成员之间插入可能的填充字节,或者在最后一个成员之后插入,以确保每个成员正确对齐.
gcc提供了一种语言扩展,__attribute__((packed))它告诉编译器不要插入填充,允许结构成员不对齐.例如,如果系统通常要求所有int对象都具有4字节对齐,则__attribute__((packed))可能导致int在奇数偏移处分配struct成员.
引用gcc文档:
`packed'属性指定变量或结构字段应该具有尽可能小的对齐 - 变量的一个字节和字段的一个位,除非您使用`aligned'属性指定更大的值.
显然,使用此扩展可以导致更小的数据要求但代码更慢,因为编译器必须(在某些平台上)生成代码,以便一次一个字节地访问未对齐的成员.
但有任何不安全的情况吗?编译器是否始终生成正确(但速度较慢)的代码来访问打包结构的未对齐成员?在所有情况下都可以这样做吗?
我有项目我从32位窗口移植到64位,其中包括可简化如下的代码;
void FuncA(double &x)
{
x = 0;
}
void FuncB(double *x)
{
*x = 0;
}
#pack(1)
struct
{
char c;
double x;
} MyStruct;
#pack();
void MyFunc()
{
MyStruct M;
FuncA(M.x); // This is OK
FuncB(&M.x); // This generates a warning C4366
}
Run Code Online (Sandbox Code Playgroud)
在针对64位的VS2010 SP1下进行编译时FuncB,使用压缩结构的成员进行调用会生成以下警告;
警告C4366:一元'&'运算符的结果可能是未对齐的
虽然打电话FuncA没有.我原以为这两种情况都会编译成几乎相同的代码.引用在某些方面比对等指针更安全吗?或者MSVC根本不发出警告应该在哪里?该项目需要维护结构包装,因此我的选择是要么FuncB改为
void FuncB(__unaligned double *x)
{
*x = 0;
}
Run Code Online (Sandbox Code Playgroud)
或者只是FuncA在所有这些情况下使用.后者是更好的,因为它更便携,但我想知道它是否会起作用或者在参考案例中缺少警告只是编译器中的一个缺点.
编辑: 此错误的Microsoft帮助条目在这里.该__unaligned帮助表明,没有理会这一警告会导致异常要在安腾处理器抛出.围绕MSDN的进一步拖网表明,可能存在围绕未对齐引用的问题.虽然这可能不会给我当前的用户带来问题,但如果Itanium架构在未来得到更广泛的使用,我可能会设置一个支持噩梦.Plan现在是为使用压缩结构的所有函数添加特定包装器,以避免使用指针和__unaligned关键字.