考虑:
struct mystruct_A
{
char a;
int b;
char c;
} x;
struct mystruct_B
{
int b;
char a;
} y;
Run Code Online (Sandbox Code Playgroud)
结构的尺寸分别为12和8.
这些结构是填充还是包装?
什么时候进行填充或包装?
在C中,编译器将按照声明它们的顺序布置结构的成员,在成员之间插入可能的填充字节,或者在最后一个成员之后插入,以确保每个成员正确对齐.
gcc提供了一种语言扩展,__attribute__((packed))它告诉编译器不要插入填充,允许结构成员不对齐.例如,如果系统通常要求所有int对象都具有4字节对齐,则__attribute__((packed))可能导致int在奇数偏移处分配struct成员.
引用gcc文档:
`packed'属性指定变量或结构字段应该具有尽可能小的对齐 - 变量的一个字节和字段的一个位,除非您使用`aligned'属性指定更大的值.
显然,使用此扩展可以导致更小的数据要求但代码更慢,因为编译器必须(在某些平台上)生成代码,以便一次一个字节地访问未对齐的成员.
但有任何不安全的情况吗?编译器是否始终生成正确(但速度较慢)的代码来访问打包结构的未对齐成员?在所有情况下都可以这样做吗?
可能重复:
为什么GCC不优化结构?
为什么C++不能使结构更紧凑?
请考虑以下32位x86计算机上的示例:
由于对齐约束,以下结构
struct s1 {
char a;
int b;
char c;
char d;
char e;
}
Run Code Online (Sandbox Code Playgroud)
如果成员被重新排序,则可以更有效地表示内存(12对8字节)
struct s2 {
int b;
char a;
char c;
char d;
char e;
}
Run Code Online (Sandbox Code Playgroud)
我知道C/C++编译器不允许这样做.我的问题是为什么语言是这样设计的.毕竟,我们最终可能会浪费大量的内存,而且struct_ref->b不会关心差异.
编辑:谢谢大家的非常有用的答案.您解释为什么由于语言的设计方式,重新排列不起作用.然而,它让我想到:如果重新排列是语言的一部分,这些论点是否仍然有效?让我们说有一些指定的重新排列规则,我们至少需要这个规则
我一个接一个地论证你的论点:
低级别的数据映射,"最惊喜的元素":只写你的结构以紧身款式自己(像@佩里的回答),并没有发生任何改变(要求1).如果由于一些奇怪的原因,你想要内部填充,你可以使用虚拟变量手动插入,和/或可能有关键字/指令.
编译器差异:要求3消除了这种担忧.实际上,从@David Heffernan的评论来看,我们今天似乎遇到了这个问题,因为不同的编译器填充不同?
优化:重新排序的重点是(内存)优化.我在这看到很多潜力.我们可能无法一起删除填充,但我没有看到重新排序如何以任何方式限制优化.
类型铸造:在我看来,这是最大的问题.不过,应该有办法解决这个问题.由于规则是用语言修复的,编译器能够弄清楚成员的重新排序方式,并做出相应的反应.如上所述,在您想要完全控制的情况下,始终可以防止重新排序.此外,要求2确保类型安全代码永远不会中断.
我认为这样的规则有意义的原因是因为我发现按结构内容而不是按类型对结构成员进行分组更为自然.当我有很多内部结构时,编译器也更容易选择最适合我的顺序.最佳布局甚至可能是我无法以类型安全的方式表达的布局.另一方面,它似乎使语言更复杂,这当然是一个缺点.
请注意,我不是在谈论改变语言 - 只有它可以(/应该)设计不同.
我知道我的问题是假设的,但我认为讨论提供了对机器和语言设计较低层次的更深入的了解.
我在这里很新,所以我不知道是否应该为此产生一个新问题.请告诉我是否是这种情况.
我正在使用32位机器,所以我认为内存对齐应该是4个字节.说我有结构:
typedef struct {
unsigned short v1;
unsigned short v2;
unsigned short v3;
} myStruct;
Run Code Online (Sandbox Code Playgroud)
实际大小是6个字节,我想对齐大小应该是8,但sizeof(myStruct)返回6.
但是,如果我写:
typedef struct {
unsigned short v1;
unsigned short v2;
unsigned short v3;
int i;
} myStruct;
Run Code Online (Sandbox Code Playgroud)
实际大小是10个字节,对齐是12,这次sizeof(myStruct) == 12.
有人可以解释一下有什么区别吗?
考虑以下C代码:
#include <stdio.h>
struct employee
{
int id;
char name[30];
};
int main()
{
struct employee e1;
printf("%d %d %d", sizeof(e1.id), sizeof(e1.name), sizeof(e1));
return(0);
}
Run Code Online (Sandbox Code Playgroud)
输出是:
4 30 36
为什么结构的大小不等于其各个组件变量的大小总和?
从下面的代码sizeof(Base) == 24和sizeof(Derived) == 24.
为什么他们的尺寸相同?
在Base课堂上我们有3名成员,在Derived课堂上我们有另一名成员.
class Base
{
private:
double d;
protected:
long l;
public:
int i;
};
class Derived : public Base
{
private:
float f;
};
Run Code Online (Sandbox Code Playgroud) 例如,我有一个class,
class naive {
public:
char a;
long long b;
char c;
int d;
};
根据我的测试程序,a对d被陆续建成,像
a------- bbbbbbbb c---dddd
- 意味着未使用
为什么C++不能让它变得更紧,比如
ac--dddd bbbbbbbb
可能重复:
C中结构和联合之间的差异
我能理解结构意味着什么.但是,我对union和struct之间的区别感到困惑.联盟就像是记忆的一部分.究竟是什么意思.
当我只运行代码片段时
int *t;
std::cout << sizeof(char) << std::endl;
std::cout << sizeof(double) << std::endl;
std::cout << sizeof(int) << std::endl;
std::cout << sizeof(t) << std::endl;
Run Code Online (Sandbox Code Playgroud)
它给我一个这样的结果:
1
8
4
4
Run Code Online (Sandbox Code Playgroud)
总计:17.
但是,当我测试包含这些数据类型的sizeof结构时,它给了我24,我很困惑.额外的7个字节是多少?
这是代码
#include <iostream>
#include <stdio.h>
struct struct_type{
int i;
char ch;
int *p;
double d;
} s;
int main(){
int *t;
//std::cout << sizeof(char) <<std::endl;
//std::cout << sizeof(double) <<std::endl;
//std::cout << sizeof(int) <<std::endl;
//std::cout << sizeof(t) <<std::endl;
printf("s_type is %d byes long",sizeof(struct struct_type));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
:编辑
我已经像这样更新了我的代码
#include <iostream> …Run Code Online (Sandbox Code Playgroud) 假设我有两个类,它们的内存布局应该完全相同:
struct A {
int x;
int y;
};
/* possibly more code */
struct B {
int a;
int b;
};
Run Code Online (Sandbox Code Playgroud)
标准中是否有什么可以保证我可以安全地使用static_assert(sizeof(A) == sizeof(B))?
作为较弱的变体,请考虑
struct C {
int a;
};
static_assert( sizeof(A) >= sizeof(C) ); // can this ever fail?
static_assert( sizeof(A) > sizeof(C) ); // can this ever fail?
Run Code Online (Sandbox Code Playgroud)
这个问题引发了这个问题。我天真地希望不会有任何断言失败,但是可以保证吗?