C++中的数据对齐问题

进化中 2014-03-04 04:26:07
请问各位,在C++中,在数据对齐时,是不是只要是字节数相同,不管其类型是否相同,都可以进行合并?
比如下面的类中,a和b是可以合并?
class A
{
public:
double d;
int a;
float b;
char c;
A();
~A();
}

那么,sizeof(A)是32还是24呢?
...全文
409 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
进化中 2014-03-12
  • 打赏
  • 举报
回复
引用 13 楼 zilaishuichina 的回复:
[quote=引用 11 楼 lxitong 的回复:] 为什么char会在int之后的四个字节里面呢,他为什么不会另起一行,自己独占8个字节呢?
首先 几个概念: 1.基本数据类型的自身对齐值:char自身对齐值为1,short为2,int,float为4,double为8,单位字节。 2.结构体或者类的自身对齐值:其成员变量中自身对齐值最大的那个值。 3.指定对齐值:#pragma pack (n)时的指定的对齐值n。 那么数据成员、结构体以及类最终按照几字节对齐:自身对齐值和指定对齐值中小的那个值。 然后有个公式: 存放起始地址 % 各个成员的自身对齐值 = 0 现在我们来看这个类
class A
{
public:
double d;
int a;
char c;
float b;
A();
~A();
};
这里没有指定对齐值(就是没有#pragma pack (n)) 那么这个类的的最终的对齐值是 8,就是按照8字节对齐 假定 地址空间从0x0000开始排放, 那么double d的地址为 0x0000 (0x0000 % 8 = 0) 然后往后偏8字节之后,能被下一个成员int a这4字节对齐值整除的地址为0x0008 那么int a的地址为 0x0008 (0x0008 % 4 = 0) 然后往后偏4字节之后,能被char c这1字节对齐值整除的地址为0x000C 那么char c的地址为 0x000C (0x000C % 1 = 0) 然后往后偏1字节之后,能被float b这4字节对齐值整除的地址为0x0010(此时char c后面空出来了3字节) 那么float b的地址为 0x0010 (0x0010 % 4 = 0)[/quote] 太谢谢您了,我终于明白了。
帅得不敢出门 2014-03-07
  • 打赏
  • 举报
回复
跟编译器的默认对齐大小有关 gcc 是4 vs是8 gcc下结果是20而不是24,也不是32
赵4老师 2014-03-07
  • 打赏
  • 举报
回复
#include <stdio.h>
#define field_offset(s,f) (int)(&(((struct s *)(0))->f))
struct AD  { int a; char b[13]; double c;};
#pragma pack(push)
#pragma pack(1)
struct A1  { int a; char b[13]; double c;};
#pragma pack(2)
struct A2  { int a; char b[13]; double c;};
#pragma pack(4)
struct A4  { int a; char b[13]; double c;};
#pragma pack(8)
struct A8  { int a; char b[13]; double c;};
#pragma pack(16)
struct A16 { int a; char b[13]; double c;};
#pragma pack(pop)
int main() {
    printf("AD.a %d\n",field_offset(AD,a));
    printf("AD.b %d\n",field_offset(AD,b));
    printf("AD.c %d\n",field_offset(AD,c));
    printf("\n");
    printf("A1.a %d\n",field_offset(A1,a));
    printf("A1.b %d\n",field_offset(A1,b));
    printf("A1.c %d\n",field_offset(A1,c));
    printf("\n");
    printf("A2.a %d\n",field_offset(A2,a));
    printf("A2.b %d\n",field_offset(A2,b));
    printf("A2.c %d\n",field_offset(A2,c));
    printf("\n");
    printf("A4.a %d\n",field_offset(A4,a));
    printf("A4.b %d\n",field_offset(A4,b));
    printf("A4.c %d\n",field_offset(A4,c));
    printf("\n");
    printf("A8.a %d\n",field_offset(A8,a));
    printf("A8.b %d\n",field_offset(A8,b));
    printf("A8.c %d\n",field_offset(A8,c));
    printf("\n");
    printf("A16.a %d\n",field_offset(A16,a));
    printf("A16.b %d\n",field_offset(A16,b));
    printf("A16.c %d\n",field_offset(A16,c));
    printf("\n");
    return 0;
}
//AD.a 0
//AD.b 4
//AD.c 24
//
//A1.a 0
//A1.b 4
//A1.c 17
//
//A2.a 0
//A2.b 4
//A2.c 18
//
//A4.a 0
//A4.b 4
//A4.c 20
//
//A8.a 0
//A8.b 4
//A8.c 24
//
//A16.a 0
//A16.b 4
//A16.c 24
//
//
匚匚 2014-03-07
  • 打赏
  • 举报
回复
资源紧张时可以考虑一下这个
zilaishuichina 2014-03-07
  • 打赏
  • 举报
回复
引用 11 楼 lxitong 的回复:
为什么char会在int之后的四个字节里面呢,他为什么不会另起一行,自己独占8个字节呢?
至于什么 为什么不会另起一行 这只不过是我画图的时候 以8个字节为一行画的 实际内存是线性的 没有这个一行一行的概念 如果画成4个字节为1行, 那这个char c不就是在int的下一行的了么,那么double就占2行是吧 甚至于 你画成2个字节一行也行 double占4行, int 和 float占2行
zilaishuichina 2014-03-07
  • 打赏
  • 举报
回复
引用 11 楼 lxitong 的回复:
为什么char会在int之后的四个字节里面呢,他为什么不会另起一行,自己独占8个字节呢?
首先 几个概念: 1.基本数据类型的自身对齐值:char自身对齐值为1,short为2,int,float为4,double为8,单位字节。 2.结构体或者类的自身对齐值:其成员变量中自身对齐值最大的那个值。 3.指定对齐值:#pragma pack (n)时的指定的对齐值n。 那么数据成员、结构体以及类最终按照几字节对齐:自身对齐值和指定对齐值中小的那个值。 然后有个公式: 存放起始地址 % 各个成员的自身对齐值 = 0 现在我们来看这个类
class A
{
public:
double d;
int a;
char c;
float b;
A();
~A();
};
这里没有指定对齐值(就是没有#pragma pack (n)) 那么这个类的的最终的对齐值是 8,就是按照8字节对齐 假定 地址空间从0x0000开始排放, 那么double d的地址为 0x0000 (0x0000 % 8 = 0) 然后往后偏8字节之后,能被下一个成员int a这4字节对齐值整除的地址为0x0008 那么int a的地址为 0x0008 (0x0008 % 4 = 0) 然后往后偏4字节之后,能被char c这1字节对齐值整除的地址为0x000C 那么char c的地址为 0x000C (0x000C % 1 = 0) 然后往后偏1字节之后,能被float b这4字节对齐值整除的地址为0x0010(此时char c后面空出来了3字节) 那么float b的地址为 0x0010 (0x0010 % 4 = 0)
jiandingzhe 2014-03-06
  • 打赏
  • 举报
回复
不要太纠结这种事情。不同的编译器可能还不一样呢。
进化中 2014-03-06
  • 打赏
  • 举报
回复
引用 8 楼 zilaishuichina 的回复:
接上 如果你的类A写成这样
class A
{
public:
double d;
int a;
char c;
float b;
A();
~A();
}
对齐方式如下 第二行 char后3个字节 第三行 float后4字节是空的 没用
为什么char会在int之后的四个字节里面呢,他为什么不会另起一行,自己独占8个字节呢?
vipcxj 2014-03-04
  • 打赏
  • 举报
回复
http://bbs.csdn.net/topics/390713630 请参加此贴中我的回答 4L对了一部分,要补充的就是可以通过#pragma pack(n)指定对齐大小的上限,也就是打破第一条规则。毕竟如果最宽基本类型成员的长度太长了,会导致浪费空间。 还有正如LS所说,如果你真理解了对齐规则,你就根本不可能问出这个问题
「已注销」 2014-03-04
  • 打赏
  • 举报
回复
引用 5 楼 lxitong 的回复:
[quote=引用 4 楼 lijian19911012 的回复:]
class A
{
};
少个分号 1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除; 2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding); 3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要,编译器会在最末一个成员之后加上填充字节(trailing padding)。
对的,少写了分号。谢谢。但是你回答的问题不是我要问的啊,你说的这些我知道,我想问的是在类型不同时,是不是相同字节数的两个变量仍可以合并?[/quote] 你如果按照这三条去做,就不会出来相同字节数的变量合并这样的问题了。
zilaishuichina 2014-03-04
  • 打赏
  • 举报
回复
接上

如果你的类A写成这样
class A
{
public:
double d;
int a;
char c;
float b;
A();
~A();
}


对齐方式如下

第二行 char后3个字节 第三行 float后4字节是空的 没用
zilaishuichina 2014-03-04
  • 打赏
  • 举报
回复
“在数据对齐时,是不是只要是字节数相同,不管其类型是否相同,都可以进行合并”这种说法我没有听说过,不知道你说的合并时啥意思

在你的这个类中
double 是8字节
int 是4字节
float 是4字节
char 是1字节




对齐方式如图 第三行后7个字节是空的 没用
autumn1202 2014-03-04
  • 打赏
  • 举报
回复
4L的三原则说的很对, 所以编译器在计算sizeof的时候,关心的是每个成员对应的类型大小,而不是关心成员的类型,所以相同字节数的两个变量绝对是可以合并的
进化中 2014-03-04
  • 打赏
  • 举报
回复
引用 4 楼 lijian19911012 的回复:
class A
{
};
少个分号 1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除; 2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding); 3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要,编译器会在最末一个成员之后加上填充字节(trailing padding)。
对的,少写了分号。谢谢。但是你回答的问题不是我要问的啊,你说的这些我知道,我想问的是在类型不同时,是不是相同字节数的两个变量仍可以合并?
「已注销」 2014-03-04
  • 打赏
  • 举报
回复
class A
{
};
少个分号 1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除; 2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding); 3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要,编译器会在最末一个成员之后加上填充字节(trailing padding)。
进化中 2014-03-04
  • 打赏
  • 举报
回复
引用 2 楼 derekrose 的回复:
不要研究这个了 这个是编译器的工作
这是我看到的一道题目,好像是一个笔试题,所以拿出来问问。我知道如果b也是int类型的话,那么a、b是可以合并的,但是不知道在类型不同时是不是还可以合并。
derekrose 2014-03-04
  • 打赏
  • 举报
回复
不要研究这个了 这个是编译器的工作
zhcosin 2014-03-04
  • 打赏
  • 举报
回复
这个问题找度娘更容易解决。
1. C 语言的指针和内存泄漏 5 2. C语言难点分析整理 10 3. C语言难点 18 4. C/C++实现冒泡排序算法 32 5. C++指针和引用的区别 35 6. const char*, char const*, char*const的区别 36 7. C可变参数函数实现 38 8. C程序内存组成部分 41 9. C编程拾粹 42 10. C语言实现数组的动态增长 44 11. C语言的位运算 46 12. 浮点数的存储格式: 50 13. 位域 58 14. C语言函数二维数组传递方法 64 15. C语言复杂表达式的执行步骤 66 16. C语言字符串函数大全 68 17. C语言宏定义技巧 89 18. C语言实现动态数组 100 19. C语言笔试-运算符和表达式 104 20. C语言编程准则之稳定篇 107 21. C语言编程常见问题分析 108 22. C语言编程易犯毛病集合 112 23. C语言缺陷与陷阱(笔记) 119 24. C语言防止缓冲区溢出方法 126 25. C语言高效编程秘籍 128 26. C运算符优先级口诀 133 27. do/while(0)的妙用 134 28. exit()和return()的区别 140 29. exit子程序终止函数与return的差别 141 30. extern与static存储空间矛盾 145 31. PC-Lint与C\C++代码质量 147 32. spirntf函数使用大全 158 33. 二叉树的数据结构 167 34. 位运算应用口诀和实例 170 35. 内存对齐与ANSI Cstruct内存布局 173 36. 冒泡和选择排序实现 180 37. 函数指针数组与返回数组指针的函数 186 38. 右左法则- 复杂指针解析 189 39. 回车和换行的区别 192 40. 堆和堆栈的区别 194 41. 堆和堆栈的区别 198 42. 如何写出专业的C头文件 202 43. 打造最快的Hash表 207 44. 指针与数组学习笔记 222 45. 数组不是指针 224 46. 标准C字符串分割的方法 228 47. 汉诺塔源码 231 48. 洗牌算法 234 49. 深入理解C语言指针的奥秘 236 50. 游戏外挂的编写原理 254 51. 程序实例分析-为什么会陷入死循环 258 52. 空指针究竟指向了内存的哪个地方 260 53. 算术表达式的计算 265 54. 结构体对齐的具体含义 269 55. 连连看AI算法 274 56. 连连看寻路算法的思路 283 57. 重新认识:指向函数的指针 288 58. 链表的源码 291 59. 高质量的子程序 295 60. 高级C语言程序员测试必过的十六道最佳题目+答案详解 297 61. C语言常见错误 320 62. 超强的指针学习笔记 325 63. 程序员之路──关于代码风格 343 64. 指针、结构体、联合体的安全规范 346 65. C指针讲解 352 66. 关于指向指针的指针 368 67. C/C++ 误区一:void main() 373 68. C/C++ 误区二:fflush(stdin) 376 69. C/C++ 误区三:强制转换 malloc() 的返回值 380 70. C/C++ 误区四:char c = getchar(); 381 71. C/C++ 误区五:检查 new 的返回值 383 72. C 是 C++ 的子集吗? 384 73. C和C++的区别是什么? 387 74. 无条件循环 388 75. 产生随机数的方法 389 76. 顺序表及其操作 390 77. 单链表的实现及其操作 391 78. 双向链表 395 79. 程序员数据结构笔记 399 80. Hashtable和HashMap的区别 408 81. hash 表学习笔记 410 82. C程序设计常用算法源代码 412 83. C语言有头结点链表的经典实现 419 84. C语言惠通面试题 428 85. C语言常用宏定义 450

64,646

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧