C 局部变量排序问题

C 局部变量排序问题,c,local-variables,C,Local Variables,我注意到我用C编写的一些程序在我的机器上没有运行,但它们在其他机器上运行。为了测试这一点,我编写了一个简单的程序来测试堆栈如何推送和弹出局部变量: #include <stdio.h> #include <string.h> int main() { char char_test[10]; int int_test = 0; strcpy(char_test, "Hello"); } #include <stdio.h> #inc

我注意到我用C编写的一些程序在我的机器上没有运行,但它们在其他机器上运行。为了测试这一点,我编写了一个简单的程序来测试堆栈如何推送和弹出局部变量:

#include <stdio.h>
#include <string.h>

int main() {
    char char_test[10];
    int int_test = 0;

    strcpy(char_test, "Hello");
}
#include <stdio.h>
#include <string.h>

int main() {
    char char_test[10];
    int int_test = 0;

    strcpy(char_test, "Hello");

    printf("Address of char_test: 0x%x\n", &char_test);
    printf("Address of int_test: 0x%x\n", &int_test);
}
#包括
#包括
int main(){
char_试验[10];
int_检验=0;
strcpy(字符测试,“你好”);
}
然后我调试了这个程序,发现int_test的内存地址比char_test高,尽管据我所知,第一个声明的局部变量应该具有更高的内存地址。然后,我添加了两个打印函数,用于打印变量的内存地址:

#include <stdio.h>
#include <string.h>

int main() {
    char char_test[10];
    int int_test = 0;

    strcpy(char_test, "Hello");
}
#include <stdio.h>
#include <string.h>

int main() {
    char char_test[10];
    int int_test = 0;

    strcpy(char_test, "Hello");

    printf("Address of char_test: 0x%x\n", &char_test);
    printf("Address of int_test: 0x%x\n", &int_test);
}
#包括
#包括
int main(){
char_试验[10];
int_检验=0;
strcpy(字符测试,“你好”);
printf(“字符测试地址:0x%x\n”,&char\u测试);
printf(“int\u测试地址:0x%x\n”,&int\u测试);
}

现在,第一个局部变量的内存地址比第二个高。打印地址是否会改变变量的顺序?我做错什么了吗?

内存中变量的顺序是编译器的一个实现细节

它可以将它们按顺序排列,或按相反顺序排列,或按数据类型分组,或以其他方式排列。这在不同的编译器中是不同的,也可能因不同的优化级别而有所不同。另外,正如您所看到的,使用哪种策略可能会随着看似无关的代码更改而更改


C标准对如何实现这一点没有任何要求,因此您不能依赖于它们的顺序进行移植。

您所指的顺序要求适用于
struct
s的成员。编译器不需要以这种或那种方式对局部变量进行排序。事实上,编译器不需要为其自动变量使用堆栈,甚至根本不需要分配它们,只要它能够成功


在您的示例中,编译器似乎就是这样做的:由于未使用
int\u test
,编译器假装它不存在。一旦您通过获取地址开始使用它,编译器就被迫分配它。它碰巧在字符测试之前分配了变量,但它没有义务这样做。

内存中变量的顺序(无论是局部变量还是全局变量)与任何合理的程序无关

当然,已经有缺陷的程序的行为可能取决于变量的相对接近度(特别是溢出的数组),但这显然是因为程序已经有缺陷了


而且,没有任何规则可以控制,也不能保证编译器(和链接器)将如何分配地址。

A好的,内存中局部变量的排列不是用C定义的,因此编译器可以自由地以任何方便的方式进行设置。您需要知道这一点是有原因的吗?我试图了解缓冲区溢出,变量的顺序似乎非常重要。编译器可能会对变量进行重新排序(因为每个人都注意到允许这样做),因为
int
需要在特定的边界上,而
char
则不需要。对于许多现代32位机器来说,
int
需要在4字节边界上,因此将
char
数组放在首位将需要浪费2个填充字节。(当然,堆栈可能也必须对齐,因此这两个字节无论如何都必须浪费!)要处理缓冲区溢出,可以尝试将变量放入结构中。我不确定编译器在重新排序结构成员时是否具有同样的灵活性,尽管它显然必须遵守对齐限制。旁白:打印指针值应该是
printf(“int\u测试地址:0x%p\n”,(void*)&int\u测试)。还可以考虑如何使用64位指针和32位<代码>无符号int 来执行版本。不应该先推吗?所以完全不可能预测变量的排序方式吗?@nope122一般来说,是的,这是不可能的。显然,任何特定的编译器都会有自己的模式,您可能会找到这些模式。