c++ - 基本数据对齐问题

标签 c++ visual-c++ low-level

我一直在研究我的计算机在引擎盖下是如何工作的。我感兴趣的是看到函数内部堆栈上发生的事情。为此,我编写了以下玩具程序:

#include <stdio.h>

void __cdecl Test1(char a, unsigned long long b, char c)
{
    char c1;
    unsigned long long b1;
    char a1;
    c1 = 'b';
    b1 = 4;
    a1 = 'r';
    printf("%d %d - %d - %d %d Total: %d\n", 
        (long)&b1 - (long)&a1, (long)&c1 - (long)&b1,
        (long)&a - (long)&c1,
        (long)&b - (long)&a, (long)&c - (long)&b,
        (long)&c - (long)&a1
        );
};

struct TestStruct
{
    char a;
    unsigned long long b;
    char c;
};

void __cdecl Test2(char a, unsigned long long b, char c)
{
    TestStruct locals;
    locals.a = 'b';
    locals.b = 4;
    locals.c = 'r';
    printf("%d %d - %d - %d %d Total: %d\n", 
        (long)&locals.b - (long)&locals.a, (long)&locals.c - (long)&locals.b,
        (long)&a - (long)&locals.c,
        (long)&b - (long)&a, (long)&c - (long)&b,
        (long)&c - (long)&locals.a
        );
};

int main()
{
    Test1('f', 0, 'o');
    Test2('f', 0, 'o');
    return 0;
}

这会吐出以下内容:

9 19 - 13 - 4 8 总计:53

8 8 - 24 - 4 8 总计:52

函数 args 表现良好,但由于指定了调用约定,我希望如此。但是局部变量有点不稳定。我的问题是,为什么这些不一样?第二次调用似乎产生了一个更紧凑和更好对齐的堆栈。

查看 ASM 是没有启发性的(至少对我而言),因为那里的变量地址仍然是别名。所以我想这确实是一个关于汇编程序本身将堆栈分配给局部变量的问题。

我知道任何特定的答案都可能是特定于平台的。我对一般解释更感兴趣,除非这个怪癖真的是特定于平台的。不过郑重声明,我是在 64 位 Intel 机器上使用 VS2010 进行编译。

最佳答案

POD 结构的内存布局几乎由您平台上的语言规则 + 类型对齐/大小要求指定和保证。

实现可以自由处理局部变量和函数参数。很可能它只是将其中一些放入堆栈,因为您使用一元 & 运算符获取它们的地址。

当不使用局部变量时,编译器可能会优化它的初始化。当非常密集地使用局部简单变量时,编译器可能会为其使用寄存器。当局部变量只使用一次时,编译器可以直接使用它的值来代替用法。

如果你想更好地指定/保证功能参数布局,那么你必须使用外部“C”链接。

关于c++ - 基本数据对齐问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4534766/

相关文章:

c++随机列表元素不被循环删除

visual-c++ - 如何在OpenCV的Mat中存储和访问图像

c++ - 在 VS2010 中使用 list_of 调用不明确

c++ - 如何在同一个类中使用重载运算符 []?

java - 使用 Java 获取全局键盘输入

大于2GB的SD卡的Android低级读取

winapi - 来自 Windows 的低级键盘输入

java - 使用 STL/POSIX 将二进制文件从 J2SE 加载到 iOS iphone

c++ - ifstream::open() 到底做了什么?

c++ - 如果 'foo' 是引用变量, [&foo]{ ... } 捕获和 [foo]{ ... } 捕获之间有区别吗?