我有一个C#背景.我非常喜欢像C这样的低级语言.
在C#中,struct默认情况下由编译器布局内存.编译器可以隐式地重新排序数据字段或填充字段之间的附加位.因此,我必须指定一些特殊属性来覆盖此行为以获得精确布局.
AFAIK,C struct默认情况下不重新排序或对齐a的内存布局.但是,我听说有一个很难找到的例外.
什么是C的内存布局行为?什么应该重新订购/对齐而不是?
[不是结构填充和包装的重复。这个问题是关于填充的方式和时间。这是关于如何处理它的信息。]
我刚刚意识到C ++中的对齐会浪费多少内存。考虑以下简单示例:
struct X
{
int a;
double b;
int c;
};
int main()
{
cout << "sizeof(int) = " << sizeof(int) << '\n';
cout << "sizeof(double) = " << sizeof(double) << '\n';
cout << "2 * sizeof(int) + sizeof(double) = " << 2 * sizeof(int) + sizeof(double) << '\n';
cout << "but sizeof(X) = " << sizeof(X) << '\n';
}
Run Code Online (Sandbox Code Playgroud)
使用g ++时,程序将提供以下输出:
sizeof(int) = 4
sizeof(double) = 8
2 * sizeof(int) + sizeof(double) = 16
but …Run Code Online (Sandbox Code Playgroud) c++ optimization memory-alignment memory-layout struct-member-alignment
在 K&R(C 编程语言第 2 版)第 5 章中,我阅读了以下内容:
首先,在某些情况下可以比较指针。如果
p和q指向同一个数组的成员,则关系一样==,!=,<,>=,等正常工作。
这似乎意味着只能比较指向同一数组的指针。
但是,当我尝试此代码时
char t = 't';
char *pt = &t;
char x = 'x';
char *px = &x;
printf("%d\n", pt > px);
Run Code Online (Sandbox Code Playgroud)
1 被打印到屏幕上。
首先,我认为我会得到 undefined 或某种类型或错误,因为pt和px没有指向同一个数组(至少在我的理解中)。
也是pt > px因为两个指针都指向存储在栈上的变量,栈向下增长,所以内存地址t大于x?为什么pt > px是真的?
当 malloc 被引入时,我变得更加困惑。 同样在第 8.7 章的 K&R 中写到以下内容:
然而,仍然存在一种假设,即
sbrk可以有意义地比较指向由 返回的不同块的指针。仅允许在数组内进行指针比较的标准并不能保证这一点。因此,这个版本的malloc仅在一般指针比较有意义的机器之间是可移植的。
将指向堆上 malloced …
在c/c ++中(我假设它们在这方面是相同的),如果我有以下内容:
struct S {
T a;
.
.
.
} s;
Run Code Online (Sandbox Code Playgroud)
以下是否保证是真的?
(void*)&s == (void*)&s.a;
Run Code Online (Sandbox Code Playgroud)
或者换句话说,是否有任何保证在第一个成员之前没有填充?
在Ubuntu x86系统上反汇编ELF二进制文件我不禁注意到代码(.text)部分从虚拟地址0x8048000开始,所有较低的内存地址似乎都未使用.
这似乎相当浪费,所有谷歌出现都是涉及STACK_TOP的民间传说或防止空指针解除引用.后一种情况看起来可以通过使用单个页面来修复,而不是留下128MB的间隙.
所以我的问题是 - 对于为什么布局已经固定到这些值或者它只是一个随意的选择,有一个确定的答案吗?
在我的第一个例子中,我使用了两个位域int64_t.当我编译并获得类的大小时,我得到8.
class Test
{
int64_t first : 40;
int64_t second : 24;
};
int main()
{
std::cout << sizeof(Test); // 8
}
Run Code Online (Sandbox Code Playgroud)
但是,当我将第二个bitfeild更改int32_t为类的大小时,会增加到16:
class Test
{
int64_t first : 40;
int32_t second : 24;
};
int main()
{
std::cout << sizeof(Test); // 16
}
Run Code Online (Sandbox Code Playgroud)
这种情况发生在GCC 5.3.0和MSVC 2015上.但为什么呢?
据我所知,Rust编译器允许打包,重新排序和添加填充到结构的每个字段.如果需要,我如何指定精确的内存布局?
在C#中,我有StructLayout属性,在C/C++中,我可以使用各种编译器扩展.我可以通过检查预期值位置的字节偏移来验证内存布局.
我想使用自定义着色器编写OpenGL代码,这需要精确的内存布局.有没有办法在不牺牲性能的情况下做到这一点?
引用是否具有存储位置,或者仅仅是另一个位置的别名?这是否因C ++版本不同而不同,或者是否与C ++的所有版本都一致?并且,如果引用具有存储位置,那么它是否只允许在类型之类的指针上使用值语义?
像这样使用参考如何工作:
struct aStruct{
int aVariable;
aClass& aReferencetoaClass;
};
Run Code Online (Sandbox Code Playgroud)
它会占用空间还是别名?
c++ reference memory-layout language-lawyer storage-duration
考虑以下简单结构:
struct A
{
float data[16];
};
Run Code Online (Sandbox Code Playgroud)
假设平台上float有32位IEEE754浮点数(如果很重要),那么C ++标准是否可以保证预期的内存布局struct A?如果不是,它将提供什么保证和/或执行保证的方式是什么?
由预期存储器布局我的意思是该结构占用16*4=64在存储器字节,每个连续4字节占用由单个float从data阵列。换句话说,预期的内存布局意味着以下测试通过:
static_assert(sizeof(A) == 16 * sizeof(float));
static_assert(offsetof(A, data[0]) == 0 * sizeof(float));
static_assert(offsetof(A, data[1]) == 1 * sizeof(float));
...
static_assert(offsetof(A, data[15]) == 15 * sizeof(float));
Run Code Online (Sandbox Code Playgroud)
(offsetof这里是合法的,因为A是标准布局,请参见下文)
万一这困扰您,测试实际上会通过 gcc 9 HEAD在wandbox上通过。我从未遇到过平台和编译器的结合,它们会提供证据证明该测试可能会失败,并且我很想了解它们的存在。
alignas说明符来处理它)。write_bytes(&x, sizeof(A))。data数组以传递这种类型的单个对象,但是对于其中的一系列对象(例如,用于上传矩阵类型的顶点属性),仍然需要特定的内存布局。 …作为一个编程练习,我在C中编写了一个标记 - 清除垃圾收集器.我希望扫描数据段(全局等)以获得指定内存的指针,但我不知道如何获取范围该段的地址.我怎么能这样做?
c garbage-collection memory-management global-variables memory-layout
memory-layout ×10
c++ ×5
c ×4
bit-fields ×1
elf ×1
heap-memory ×1
linux ×1
optimization ×1
pointers ×1
reference ×1
rust ×1
struct ×1
x86 ×1