假设这个 C 代码:
int main(){
int n;
scanf("%d\n", &n);
int a[n];
int i;
for (i = 0; i<n; i++){
a[i] = 1;
}
}
我们有一个在堆栈空间中的向量,但是直到执行时间(直到用户给变量 n 赋值)我们才知道向量的大小。所以我的问题是:何时以及如何为堆栈部分中的该向量保留空间?
直到现在我才明白堆栈空间是在编译时保留的,而堆空间是在运行时保留的(使用 malloc 之类的函数)。但是直到运行时我们才能知道这个向量的大小。
我认为可以做的是在知道它的那一刻从堆栈指针中减去 n 的值,从而扩大该函数的堆栈以使向量适合(我提到的这种减法只能在汇编代码)。
但是我一直在做一些测试来观察 /proc/[pid]/maps 的内容。并且进程的堆栈空间没有改变,所以我认为(在汇编代码中将 n*sizeof(int) 减去堆栈顶部的指令)没有完成。我在 main 函数的开头和结尾都看过 /proc/[pid]/maps 的内容。
如果我为 x86 (gcc -m32 -o test.c) 汇编这段代码,你会得到以下汇编代码(以备不时之需):
.file "test.c"
.text
.section .rodata
.LC0:
.string "%d\n"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
leal 4(%esp), %ecx
.cfi_def_cfa 1, 0
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
.cfi_escape 0x10,0x5,0x2,0x75,0
movl %esp, %ebp
pushl %esi
pushl %ebx
pushl %ecx
.cfi_escape 0xf,0x3,0x75,0x74,0x6
.cfi_escape 0x10,0x6,0x2,0x75,0x7c
.cfi_escape 0x10,0x3,0x2,0x75,0x78
subl $44, %esp
call __x86.get_pc_thunk.ax
addl $_GLOBAL_OFFSET_TABLE_, %eax
movl %gs:20, %ecx
movl %ecx, -28(%ebp)
xorl %ecx, %ecx
movl %esp, %edx
movl %edx, %esi
subl $8, %esp
leal -44(%ebp), %edx
pushl %edx
leal .LC0@GOTOFF(%eax), %edx
pushl %edx
movl %eax, %ebx
call __isoc99_scanf@PLT
addl $16, %esp
movl -44(%ebp), %eax
leal -1(%eax), %edx
movl %edx, -36(%ebp)
sall $2, %eax
leal 3(%eax), %edx
movl $16, %eax
subl $1, %eax
addl %edx, %eax
movl $16, %ebx
movl $0, %edx
divl %ebx
imull $16, %eax, %eax
subl %eax, %esp
movl %esp, %eax
addl $3, %eax
shrl $2, %eax
sall $2, %eax
movl %eax, -32(%ebp)
movl $0, -40(%ebp)
jmp .L2
.L3:
movl -32(%ebp), %eax
movl -40(%ebp), %edx
movl $1, (%eax,%edx,4)
addl $1, -40(%ebp)
.L2:
movl -44(%ebp), %eax
cmpl %eax, -40(%ebp)
jl .L3
movl %esi, %esp
movl $0, %eax
movl -28(%ebp), %ecx
xorl %gs:20, %ecx
je .L5
call __stack_chk_fail_local
.L5:
leal -12(%ebp), %esp
popl %ecx
.cfi_restore 1
.cfi_def_cfa 1, 0
popl %ebx
.cfi_restore 3
popl %esi
.cfi_restore 6
popl %ebp
.cfi_restore 5
leal -4(%ecx), %esp
.cfi_def_cfa 4, 4
ret
.cfi_endproc
.LFE0:
.size main, .-main
.section .text.__x86.get_pc_thunk.ax,"axG",@progbits,__x86.get_pc_thunk.ax,comdat
.globl __x86.get_pc_thunk.ax
.hidden __x86.get_pc_thunk.ax
.type __x86.get_pc_thunk.ax, @function
__x86.get_pc_thunk.ax:
.LFB1:
.cfi_startproc
movl (%esp), %eax
ret
.cfi_endproc
.LFE1:
.hidden __stack_chk_fail_local
.ident "GCC: (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0"
.section .note.GNU-stack,"",@progbits