Đúng rồi. Kể cả chung vùng nhớ nhưng khác bao đóng {} thì 2 biến trùng tên vẫn ok. Khi hàm được gọi đến thì các biến sẽ push lên stack, hết bao đóng là thoát khỏi stack frame, chuyển sang stack frame mới.
Không phải lúc nào biến cũng được đưa lên stack.
Nếu vẫn còn thừa thanh ghi thì trình dịch có thể để ngay tại đó luôn. Nhất là loại biến dùng xong rồi vứt.
Ví dụ với ngay chương trình ở #1, khi compile ở chế độ -O2 thì trình dịch hoàn toàn không dùng stack để chứa giá trị các biến:
https://gcc.godbolt.org/z/fMsKj6zsv
.LC0:
.string "x (in sub block) = %d\n"
.LC1:
.string "n = %d\n"
.LC2:
.string "x (int main block) = %d\n"
.LC3:
.string "y = %d\n"
main:
sub rsp, 8
mov esi, 4
mov edi, OFFSET FLAT:.LC0
xor eax, eax
call printf
mov esi, DWORD PTR n[rip]
mov edi, OFFSET FLAT:.LC1
xor eax, eax
call printf
mov esi, 5
mov edi, OFFSET FLAT:.LC2
xor eax, eax
call printf
mov esi, 7
mov edi, OFFSET FLAT:.LC3
xor eax, eax
call printf
mov esi, -7
mov edi, OFFSET FLAT:.LC1
xor eax, eax
call printf
xor eax, eax
add rsp, 8
ret
n:
.long 5
Để ý thấy không có chỗ nào trong đoạn code đụng đến thanh ghi stack rsp, trừ đoạn setup frame ở đầu và cuối. Biến lưu vào thanh ghi khác hết.