字节对齐

还是自己记录一下吧,因为没有被字节对齐坑过可能每次看了就忘记了。每次面试的时候还总是会有,我每次都会有些模糊。还是眼过千遍不如手过一遍,今天看到一个微软的面试题关于字节对齐,自以为记得内存对齐,自己算了一遍,然后一看下面答案就发现了,自己记错了。虽然记得大概却总是会混乱,我还是的记录一下。废话不说了。上菜。

今天看到的微软面试题:

好习惯标记出处来自博客:https://blog.csdn.net/dreamback1987/article/details/8504943

#include <iostream.h>
#pragma pack(8)
struct example1
{
    short a;
    long b;
};
struct example2
{
    char c;
    example1 struct1;
    short e;    
};
#pragma pack()
int main(int argc, char* argv[])
{
    example2 struct2;
    cout << sizeof(example1) << endl;
    cout << sizeof(example2) << endl;
    cout << (unsigned int)(&struct2.struct1) - (unsigned int)(&struct2) << endl;
    return 0;
}

问程序的输入结果是什么?

答案是:

8
16
4

我的错误答案:8、12、2。

可能因为我之前对字节对齐有误会哈哈。

我抱着不相信我自己记错了的态度,我又在自己电脑上测试了一番,代码如下:

//
//  main.cpp
//  test_memory_alignment
//
//  Created by Wtayu on 2019/7/29.
//  Copyright © 2019 Wtayu. All rights reserved.
//

#include <iostream>

struct A{
    char str;
    int  num;
    short s_num;
};
struct Intel{
    char c;
    short a;
    long b;
    short e;
};

struct example1{
    short a;
    int b;
};

struct example2
{
    char c;
    example1 struct1;
    short e;
};



int main(int argc, const char * argv[]) {
    //测试1
    std::cout<<"测试1:"<<std::endl;
    A a[2];
    std::cout <<"sizeof(a):" <<sizeof(a)<<std::endl;
    std::cout <<"struct a0:" << &a <<std::endl;
    std::cout <<"str:"<<(void *)&a[0].str<<std::endl;
    std::cout <<"num:" <<&a[0].num<<std::endl;
    std::cout <<"s_num:"<<&a[0].s_num<<std::endl;
    std::cout <<"a1:"<<&a[1]<<std::endl;
    //测试2
    Intel i[2];
    std::cout<<"测试2:"<<std::endl;
    std::cout <<"sizeof(Intel):" <<sizeof(Intel)<<std::endl;
    std::cout <<"struct i0:" << &i <<std::endl;
    std::cout <<"c:"<<(void *)&i[0].c<<std::endl;
    std::cout <<"a:" <<&i[0].a<<std::endl;
    std::cout <<"b:"<<&i[0].b<<std::endl;
    std::cout <<"e:"<<&i[0].e<<std::endl;
    std::cout <<"i1:"<<&i[1]<<std::endl;
    //测试3
    example2 e[2];
    std::cout<<"测试3:"<<std::endl;
    std::cout <<"sizeof(example2):" <<sizeof(example2)<<std::endl;
    std::cout <<"struct e0:" << &e <<std::endl;
    std::cout <<"e.cc:"<<(void *)&e[0].c<<std::endl;
    std::cout <<"e.struct1:" <<&e[0].struct1<<std::endl;
    std::cout <<"e.e:"<<&e[0].e<<std::endl;
    std::cout <<"e1:"<<&e[1]<<std::endl;
    return 0;
}

输出如下:

测试1:
sizeof(a):24
struct a0:0x7ffeefbff4d0
str:0x7ffeefbff4d0
num:0x7ffeefbff4d4
s_num:0x7ffeefbff4d8
a1:0x7ffeefbff4dc
测试2:
sizeof(Intel):24
struct i0:0x7ffeefbff4a0
c:0x7ffeefbff4a0
a:0x7ffeefbff4a2
b:0x7ffeefbff4a8
e:0x7ffeefbff4b0
i1:0x7ffeefbff4b8
测试3:
sizeof(example2):16
struct e0:0x7ffeefbff480
e.cc:0x7ffeefbff480
e.struct1:0x7ffeefbff484
e.e:0x7ffeefbff48c
e1:0x7ffeefbff490
Program ended with exit code: 0

发现人家是对的,我是错的。

上面大那个链接里也谈到了,自然对齐(natural alignment)ps:他翻译的是自然对界。

我自己再总结一番吧:

自然对齐:指的是编译器的默认对齐规则。对齐规则简单分为两个影响因素:1、下一个变量“大小”。2、一般就是类内“最大”的变量;一条一条来说:

针对第一条可以理解为:下一个变量的大小如果大于当前的变量。则需要给当前变量补齐。例:

char c;
int a;

当前变量为c,大小为1字节,而下一个变量大小则为4,即符合了“下一个变量的大小如果大于当前的变量”这句话。则需要给c补齐3位,需要和a一样长。

第二条则可以理解为,默认对齐规则下类的字节大小一定是类内“最大”变量字节数的倍数。

对于每个成员都符合第一条,然后判断第二个条,如果第二条不符合则在最后变量后补齐倍数所差字节。例:

char c1;
int l;
char c2;

根据第一条算的字节数为:1+补位3+4+1=9,再根据第二条,9不是最大变量4字节的倍数,补齐3位,则为12字节。

分割线

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------

有了上面的知识其实已经可以做微软那个面试题了,但是微软那个题还有个奇怪的地方就是example2内有example1的成员变量。这个其实是需要稍微修改一下第一条原则即可:下一个变量的对齐规则如果大于当前变量的对齐规则。则需要按照下一个对齐规则给当前变量补齐。这样只需要思考example1的对齐规则是多少自己,其实就是最大成员字节数4。

好了这样就可以算出来正确的答案了。

分割线

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------

那个面试题还有一个问题:

#pragma pack(8)
#pragma pack()

这个是修改自然对齐规则,也就是定义对齐规则。第一行是将对齐规则改为8,第二行则是改为默认。

第一行改为8则是将之前提到的所有补齐的标准换为8字节。这里我就不多说了,不懂就自己写demo测试吧。

写这个一为记录、二为帮助大家理解。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值