首页 > 试题广场 >

在64位编译器下用sizeof(struct A)计算出的大

[单选题]
有一个如下的结构体:
struct A{
 long a1;
 short a2;
 int a3;
 int *a4;
};
请问在64位编译器下用sizeof(struct A)计算出的大小是多少?
  • 24
  • 28
  • 16
  • 18
推荐
A
1.什么是内存对齐

假设我们同时声明两个变量:

char a;

short b;

用&(取地址符号)观察变量a,

b的地址的话,我们会发现(以16位CPU为例):

如果a的地址是0x0000,那么b的地址将会是0x0002或者是0x0004。

那么就出现这样一个问题:0x0001这个地址没有被使用,那它干什么去了? 答案就是它确实没被使用。 因为CPU每次都是从以2字节(16位CPU)或是4字节(32位CPU)的整数倍的内存地址中读进数据的。如果变量b的地址是0x0001的话,那么CPU就需要先从0x0000中读取一个short,取它的高8位放入b的低8位,然后再从0x0002中读取下一个short,取它的低8位放入b的高8位中,这样的话,为了获得b的值,CPU需要进行了两次读操作。

 

但是如果b的地址为0x0002,

那么CPU只需一次读操作就可以获得b的值了。所以编译器为了优化代码,往往会根据变量的大小,将其指定到合适的位置,即称为内存对齐(对变量b做内存对齐,a、b之间的内存被浪费,a并未多占内存)。

2.结构体内存对齐规则(请记住三条内存规则(在没有#pragam pack宏的情况下

结构体所占用的内存与其成员在结构体中的声明顺序有关,其成员的内存对齐规则如下:

(1)每个成员分别按自己的对齐字节数PPB(指定的对齐字节数,32位机默认为4)两个字节数最小的那个对齐,这样可以最小化长度。如在32bit的机器上,int的大小为4,因此int存储的位置都是4的整数倍的位置开始存储。

(2)复杂类型(如结构)的默认对齐方式是它最长的成员的对齐方式,这样在成员是复杂类型时,结构体数组的时候,可以最小化长度。

(3)结构体对齐后的长度必须是成员中最大的对齐参数(PPB)的整数倍,这样在处理数组时可以保证每一项都边界对齐。

 (4)结构体作为数据成员的对齐规则:在一个struct中包含另一个struct,内部struct应该以它的最大数据成员大小的整数倍开始存储。如 struct A 中包含 struct B, struct B 中包含数据成员 char, int, double,则 struct B 应该以sizeof(double)=8的整数倍为起始地址。

3.实例演示:

struct A

{

char a;   //内存位置:  [0]

double b;   // 内存位置: [8]...[15]

int c;    // 内存位置: [16]...[19]  ----  规则1

};        // 内存大小:sizeof(A) = (1+7) + 8 + (4+4) = 24, 补齐[20]...[23]  ----  规则3

 

struct B

{

int a,    // 内存位置: [0]...[3]

A b,       // 内存位置: [8]...[31]  ----  规则2

char c,   // 内存位置: [32]

};         // 内存大小:sizeof(B) = (4+4) + 24 + (1+7) = 40, 补齐[33]...[39]

*注释:(1+7)表示该数据成员大小为1,补齐7位;(4+4)同理。


 

编辑于 2016-01-13 12:34:28 回复(10)
第一个,8字节
第二个,2字节,加起来是10,对齐到12
第三个,4字节,加起来是16
第四个,8字节,加起来是24
 所以一共是24字节
多看看就背住了:
32位编译器:32位系统下指针占用4字节
      char :1个字节
      char*(即指针变量): 4个字节(32位的寻址空间是2^32, 即32个bit,也就是4个字节。同理64位编译器)
      short int : 2个字节
      int:  4个字节
      unsigned int : 4个字节
      float:  4个字节
      double:   8个字节
      long:   4个字节
      long long:  8个字节
      unsigned long:  4个字节
64位编译器:64位系统下指针占用8字节
      char :1个字节
      char*(即指针变量): 8个字节
      short int : 2个字节
      int:  4个字节
      unsigned int : 4个字节
      float:  4个字节
      double:   8个字节
      long:   8个字节
      long long:  8个字节
      unsigned long:  8个字节

编辑于 2017-05-09 15:23:33 回复(15)
Win64下:long 8字节、short 2字节、int 4字节、int* 8字节,C++中内存对齐,按最大长度对齐:8+(2+4+2(补齐2字节))+8 = 24字节
发表于 2015-09-08 20:28:05 回复(16)
预备知识:基本类型占用字节
在32位操作系统和64位操作系统上,基本数据类型分别占多少字节呢?

32位操作系统:

char : 1    int :4    short : 2    unsigned int : 4    long : 4    unsigned long : 4    long long : 8     float : 4    double : 8    指针 : 4

64位操作系统

char : 1    int :4    short : 2    unsigned int : 4    long : 8    unsigned long : 8    long long : 8     float : 4    double : 8    指针 : 8

内存对齐:
成员对齐有一个重要的条件,即每个成员按自己的方式对齐。其对齐的规则是:每个成员按其类型的对齐参数(通常是这个类型的大小)和指定对齐参数(这里默认是8字节)中较小的一个对齐。并且结构的长度必须为所用过的所有对齐参数的整数倍。不够就补空字节。

举例:

复制代码
struct t{
    long a;
    short b;
    int c;
    int *d; 
    char e;
}
复制代码
 

在64位操作系统中的大小。

分析:

按照声明的顺序一个一个分配内存空间。

首先 long 型变量a,在64位地址空间中,long型占8个字节,所以按照上面的对齐条件,这个成员应该按照对其参数 min(sizeof(long), 8) = 8字节来对齐,所以把这个成员存放在 0~7 内存单元中。

然后 short型变量b,在64位地址空间中,short型占2个字节,所以按照上面的对齐条件,这个成员应该按照对其参数 min(sizeof(short), 8) = 2字节来对齐,所以把这个成员存放在 8~9 内存单元中。

然后 int型变量c,在64位地址空间中,int型占4个字节,所以按照上面的对齐条件,这个成员应该按照对其参数 min(sizeof(int), 8) = 4字节来对齐,所以把这个成员存放在 12~15 内存单元中(10,11单元都不能被4整除)。

然后 int*型变量d,在64位地址空间中,指针型占8个字节,所以按照上面的对齐条件,这个成员应该按照对其参数 min(sizeof(int*), 8) = 8字节来对齐,所以把这个成员存放在 16~23 内存单元中。

然后 char型变量e,在64位地址空间中,char型占1个字节,所以按照上面的对齐条件,这个成员应该按照对其参数 min(sizeof(char), 8) = 1字节来对齐,所以把这个成员存放在 24 内存单元中。

然后整个结构体的长度必须为所有对齐参数的整数倍,当前长度为25,不是所有对齐参数整数倍,必须调整为32,才是所有参数整数倍。

所以这个结构体的长度为32。


如果结构体中出现子结构体怎么办?我们在确定子结构体的对齐参数时,应该就是它的所有成员使用的对齐参数中最大的一个。

举例:

复制代码
struct t{
    char a;
    int b;
};
struct s{
   char c;
   struct t d;
   char e;
};
复制代码
在32位操作系统下的长度。

首先确定t的大小为8,它的所有成员使用的对齐参数最大为4。

再考察s:

首先 char 型变量c,在32位地址空间中,char型占1个字节,所以按照上面的对齐条件,这个成员应该按照对其参数 min(sizeof(char), 8) = 1字节来对齐,所以把这个成员存放在 0 内存单元中。

然后 struct t型变量d,在32位地址空间中,struct t占8个字节,所以按照上面的对齐条件,这个成员应该按照对其参数 4 字节来对齐,所以把这个成员存放在 4~11 内存单元中。

然后 char型变量e,在32位地址空间中,char型占1个字节,所以按照上面的对齐条件,这个成员应该按照对其参数 min(sizeof(char), 8) = 1字节来对齐,所以把这个成员存放在 12 内存单元中。

然后整个结构体的长度必须为所有对齐参数的整数倍,当前长度为13,不是所有对齐参数整数倍,必须调整为16,才是所有参数整数倍。

所以此结构体大小为16.
发表于 2016-03-20 15:15:42 回复(4)
short 2字节对齐,int 4 ,long 8 ,int*  8. 对齐是指各成员选择 是自身倍数的地址存放
所以,地址存储为:
0-7 long ,
8-9 short ,10不是4的整数倍,int 会存放在12的位置对齐,
12-15 int ,
 16-23 int* .总大小为24,满足8的整数倍,不需要补齐。最后大小为24
发表于 2015-09-09 09:41:03 回复(1)
structA{
 longa1;
 shorta2;
 inta3;
 int*a4;
};
32位与64位字节有变化是只有指针变量、long、unsigned long:
                             32位       64位
-------------------------------------------
指针变量                 4             8
long                        4             8
unsigned long         4             8

下面每个小方框代表一个字节:(有下划线表示有内容,没有下划线表示会被自动补充)
口口口口 口口口口    // long a1: 占满了第一行8个字节
口口 口口口口  口口   // short a2 占了第二行前两个字节,紧接着int a3 顺序占了第二行第3~6这四个字节,第7、8个字节由系统自动补齐;
口口口口  口口口口    // int *a4: 占满了第三行8个字节
因此:总共3*8 = 24个字节
发表于 2016-06-27 16:36:18 回复(6)
字符长度    当前可用序号                下次可用序号
8                 0                                           8
2                 8                                           10
4               12(4的整数倍10+2)             16
4                20                                           结尾为20不是最大字符long长度8的整数倍(加4)调整为 24
发表于 2015-09-08 16:18:24 回复(3)
内存对齐的3大规则:
  1. 对于结构体的各个成员,第一个成员的偏移量是0,排列在后面的成员其当前偏移量必须是当前成员类型的整数倍
  2. 结构体内所有数据成员各自内存对齐后,结构体本身还要进行一次内存对齐,保证整个结构体占用内存大小是结构体内最大数据成员的最小整数倍
  3. 如程序中有#pragma pack(n)预编译指令,则所有成员对齐以n字节为准(即偏移量是n的整数倍),不再考虑当前类型以及最大结构体内类型
发表于 2017-09-13 12:09:19 回复(1)
win10+vs2015 64位编译器的输出结果是24,但是long占4位,所以上面很多答案虽然看起来有道理,其实不全对,部分有误导,应该是(4+2+2)+(4+4)+8=24. 不要人云亦云,实践是检验真理的唯一标准。
发表于 2017-03-08 18:18:46 回复(2)

实践是检验真理的唯一标准
环境:
图片说明

IDE:Clion

#include <cstdio>
#include <iostream>

using namespace std;

struct A{
    long a1;
    short a2;
    int a3;
    int *a4;
} a;

int main() {
    printf("%d\n", &a);          // 6295648
    printf("%d\n", &(a.a1));     // 6295648
    printf("%d\n", &(a.a2));     // 6295656
    printf("%d\n", &(a.a3));     // 6295660
    printf("%d\n", &(a.a4));     // 6295664
    printf("%d\n", sizeof(a));   // 24
    return 0;
}

打印结果:

6295648
6295648
6295656
6295660
6295664
24
编辑于 2019-03-07 22:07:24 回复(1)
发表于 2016-02-25 20:02:07 回复(0)

就是按顺序码字,不够的补字节。64位是8字节标准,寄存器MDR是64位,引脚连的数据线64根,一次性读取64bits, 共8个字节,为一个字。


第一个long 8个字节,ok,第一个字满了。第二个short 2个字节,未满,继续,第三个int 4字节,加起来6字节,未满,继续,第四个8字节,加起来就爆了,所以不能放这儿,得放到第三个字上。那第二个字只有6个字节怎么办?补俩字节。

发表于 2020-02-27 22:03:27 回复(0)
64位的编译器,根据内存对齐原则,内存对齐模数为8。第一个8位,第二个跟第三个加起来是2+4为6B,扩充为8,第三个也是8,加起来就是24!!请指正!!
发表于 2020-02-21 20:31:31 回复(0)
第一个,8字节
第二个,2字节,加起来是10,对齐到12
第三个,4字节,加起来是16
第四个,8字节,加起来是24
 所以一共是24字节
多看看就背住了:
32位编译器:32位系统下指针占用4字节
      char:1个字节
      char*(即指针变量): 4个字节(32位的寻址空间是2^32, 即32个bit,也就是4个字节。同理64位编译器)
      shortint: 2个字节
      int:  4个字节
      unsignedint: 4个字节
      float:  4个字节
      double:   8个字节
      long:   4个字节
      longlong:  8个字节
      unsignedlong:  4个字节
64位编译器:64位系统下指针占用8字节
      char:1个字节
      char*(即指针变量): 8个字节
      shortint: 2个字节
      int:  4个字节
      unsignedint: 4个字节
      float:  4个字节
      double:   8个字节
      long:   8个字节
      longlong:  8个字节
      unsignedlong:  8个字节
发表于 2017-05-31 19:53:28 回复(0)
Win64下:long 8字节、short 2字节、int 4字节、int* 8字节,C++中内存对齐,按最大长度对齐:8+(2+4+2(补齐2字节))+8 = 24字节
发表于 2015-11-03 22:11:02 回复(1)
24
4
2
4
8
所以:4+2+2(补齐2)+4+4(补齐4)+8=24

发表于 2015-09-09 10:42:31 回复(0)
C++中对齐的问题。很常见。。
发表于 2015-09-08 16:23:27 回复(0)
long是4字节,别听这些沙币扯犊子!内存对齐还有个规则是 最后的大小是内部最长类型的整数倍
发表于 2023-03-19 10:34:57 回复(0)
64位的编译器,根据内存对齐原则,内存对齐模数为8。第一个8位,第二个跟第三个加起来是2+4为6B,扩充为8,第三个也是8,加起来就是24!
发表于 2023-01-28 13:15:53 回复(0)
A
1.什么是内存对齐

假设我们同时声明两个变量:

char a;

short b;

用&(取地址符号)观察变量a,

b的地址的话,我们会发现(以16位CPU为例):

如果a的地址是0x0000,那么b的地址将会是0x0002或者是0x0004。

那么就出现这样一个问题:0x0001这个地址没有被使用,那它干什么去了? 答案就是它确实没被使用。 因为CPU每次都是从以2字节(16位CPU)或是4字节(32位CPU)的整数倍的内存地址中读进数据的。如果变量b的地址是0x0001的话,那么CPU就需要先从0x0000中读取一个short,取它的高8位放入b的低8位,然后再从0x0002中读取下一个short,取它的低8位放入b的高8位中,这样的话,为了获得b的值,CPU需要进行了两次读操作。

 

但是如果b的地址为0x0002,

那么CPU只需一次读操作就可以获得b的值了。所以编译器为了优化代码,往往会根据变量的大小,将其指定到合适的位置,即称为内存对齐(对变量b做内存对齐,a、b之间的内存被浪费,a并未多占内存)。

2.结构体内存对齐规则(请记住三条内存规则(在没有#pragam pack宏的情况下

结构体所占用的内存与其成员在结构体中的声明顺序有关,其成员的内存对齐规则如下:

(1)每个成员分别按自己的对齐字节数PPB(指定的对齐字节数,32位机默认为4)两个字节数最小的那个对齐,这样可以最小化长度。如在32bit的机器上,int的大小为4,因此int存储的位置都是4的整数倍的位置开始存储。

(2)复杂类型(如结构)的默认对齐方式是它最长的成员的对齐方式,这样在成员是复杂类型时,结构体数组的时候,可以最小化长度。

(3)结构体对齐后的长度必须是成员中最大的对齐参数(PPB)的整数倍,这样在处理数组时可以保证每一项都边界对齐。

 (4)结构体作为数据成员的对齐规则:在一个struct中包含另一个struct,内部struct应该以它的最大数据成员大小的整数倍开始存储。如 struct A 中包含 struct B, struct B 中包含数据成员 char, int, double,则 struct B 应该以sizeof(double)=8的整数倍为起始地址。

3.实例演示:

struct A

{

char a;   //内存位置:  [0]

double b;   // 内存位置: [8]...[15]

int c;    // 内存位置: [16]...[19]  ----  规则1

};        // 内存大小:sizeof(A) = (1+7) + 8 + (4+4) = 24, 补齐[20]...[23]  ----  规则3

 

struct B

{

int a,    // 内存位置: [0]...[3]

A b,       // 内存位置: [8]...[31]  ----  规则2

char c,   // 内存位置: [32]

};         // 内存大小:sizeof(B) = (4+4) + 24 + (1+7) = 40, 补齐[33]...[39]

*注释:(1+7)表示该数据成员大小为1,补齐7位;(4+4)同理。

发表于 2021-10-10 08:57:50 回复(0)
结构体所占用的内存与其成员在结构体中的声明顺序有关,其成员的内存对齐规则如下: (1)每个成员分别按自己的对齐字节数和PPB(指定的对齐字节数,32位机默认为4)两个字节数最小的那个对齐,这样可以最小化长度。如在32bit的机器上,int的大小为4,因此int存储的位置都是4的整数倍的位置开始存储。 (2)复杂类型(如结构)的默认对齐方式是它最长的成员的对齐方式,这样在成员是复杂类型时,结构体数组的时候,可以最小化长度。 (3)结构体对齐后的长度必须是成员中最大的对齐参数(PPB)的整数倍,这样在处理数组时可以保证每一项都边界对齐。  (4)结构体作为数据成员的对齐规则:在一个struct中包含另一个struct,内部struct应该以它的最大数据成员大小的整数倍开始存储。如 struct A 中包含 struct B, struct B 中包含数据成员 char, int, double,则 struct B 应该以sizeof(double)=8的整数倍为起始地址。 64位系统指针8字节
编辑于 2017-09-06 07:26:35 回复(0)