我在 C 中声明了一个变量。编译器如何为变量分配内存 space?
I declared a variable in C. How come compiler allotted a memory space for variable?
作为一个初学者,我了解到在 C 中只有变量定义分配了内存。但是对于以下程序,输出是 0x7ffd12792034
#include<stdio.h>
int main(char args[], int vargs)
{
int max;
printf("%p\n", &max);
}
A local variable is likely to sit on the call stack (but sometimes the compiler would optimize to put it only in some processor register 甚至完全忘记它)。您的 int max;
是局部变量定义。它的初始值是不确定的,这实际上意味着它保留了之前内存位置(或寄存器)中的任何内容。
您的程序正在打印调用堆栈上的局部变量的地址。
由于 ASLR 从一个程序执行到下一个程序执行,该地址的实际值可能会改变(或不变)。它是特定于实现的。
顺便说一句,你应该在编译时启用所有警告和调试信息。如果你使用 GCC, you should compile with gcc -Wall -Wextra -g
. You would then have some warnings at least, in particular because your main
function has the wrong signature. It should be int main(int argc, char**argv)
and the runtime environment guarantee that argc
is at least 1 and that the argv
array is NULL
terminated, with argc
arguments which are non-NULL
unaliased 个字符串。
在这种情况下,您实际上定义了一个变量,而不是声明一个。
如果您使用了 extern
关键字,您将有一个声明。但是因为你没有,所以你有一个定义。
int max = 1;
等初始值设定项不需要定义。该值将是未指定的,直到它被分配一个之后,但它仍然是一个定义。
如果您在没有初始值设定项的情况下在文件范围内声明变量,您将得到一个暂定定义。然后您可以稍后使用初始化器进行完整定义,但它必须与暂定定义的类型相匹配。
您正在打印内存中已占用 int max
并准备初始化的地址。通过键入 int max
,如果您给它赋值,您已经有了存储变量的位置。
C 抽象机没有像您的情况那样定义编译器将在何处分配原子数据类型。
查看特定实现的唯一方法是反汇编它。
4004d7: 55 push %rbp
4004d8: 48 89 e5 mov %rsp,%rbp
4004db: 48 83 ec 10 sub [=10=]x10,%rsp
4004df: 48 8d 45 fc lea -0x4(%rbp),%rax
4004e3: 48 89 c6 mov %rax,%rsi
4004e6: bf 84 05 40 00 mov [=10=]x400584,%edi
4004eb: b8 00 00 00 00 mov [=10=]x0,%eax
4004f0: e8 fb fe ff ff callq 4003f0 <printf@plt>
4004f5: b8 00 00 00 00 mov [=10=]x0,%eax
4004fa: c9 leaveq
4004fb: c3 retq
4004fc: 0f 1f 40 00 nopl 0x0(%rax)
在这种情况下,它在堆栈上的偏移量 -4-base_pointer
处为其分配了 space --
-0x4(%rbp)
.
作为一个初学者,我了解到在 C 中只有变量定义分配了内存。但是对于以下程序,输出是 0x7ffd12792034
#include<stdio.h>
int main(char args[], int vargs)
{
int max;
printf("%p\n", &max);
}
A local variable is likely to sit on the call stack (but sometimes the compiler would optimize to put it only in some processor register 甚至完全忘记它)。您的 int max;
是局部变量定义。它的初始值是不确定的,这实际上意味着它保留了之前内存位置(或寄存器)中的任何内容。
您的程序正在打印调用堆栈上的局部变量的地址。
由于 ASLR 从一个程序执行到下一个程序执行,该地址的实际值可能会改变(或不变)。它是特定于实现的。
顺便说一句,你应该在编译时启用所有警告和调试信息。如果你使用 GCC, you should compile with gcc -Wall -Wextra -g
. You would then have some warnings at least, in particular because your main
function has the wrong signature. It should be int main(int argc, char**argv)
and the runtime environment guarantee that argc
is at least 1 and that the argv
array is NULL
terminated, with argc
arguments which are non-NULL
unaliased 个字符串。
在这种情况下,您实际上定义了一个变量,而不是声明一个。
如果您使用了 extern
关键字,您将有一个声明。但是因为你没有,所以你有一个定义。
int max = 1;
等初始值设定项不需要定义。该值将是未指定的,直到它被分配一个之后,但它仍然是一个定义。
如果您在没有初始值设定项的情况下在文件范围内声明变量,您将得到一个暂定定义。然后您可以稍后使用初始化器进行完整定义,但它必须与暂定定义的类型相匹配。
您正在打印内存中已占用 int max
并准备初始化的地址。通过键入 int max
,如果您给它赋值,您已经有了存储变量的位置。
C 抽象机没有像您的情况那样定义编译器将在何处分配原子数据类型。
查看特定实现的唯一方法是反汇编它。
4004d7: 55 push %rbp
4004d8: 48 89 e5 mov %rsp,%rbp
4004db: 48 83 ec 10 sub [=10=]x10,%rsp
4004df: 48 8d 45 fc lea -0x4(%rbp),%rax
4004e3: 48 89 c6 mov %rax,%rsi
4004e6: bf 84 05 40 00 mov [=10=]x400584,%edi
4004eb: b8 00 00 00 00 mov [=10=]x0,%eax
4004f0: e8 fb fe ff ff callq 4003f0 <printf@plt>
4004f5: b8 00 00 00 00 mov [=10=]x0,%eax
4004fa: c9 leaveq
4004fb: c3 retq
4004fc: 0f 1f 40 00 nopl 0x0(%rax)
在这种情况下,它在堆栈上的偏移量 -4-base_pointer
处为其分配了 space --
-0x4(%rbp)
.