Tại sao bộ nhớ ngăn xếp được phân bổ khi nó không được sử dụng?


14

Hãy xem xét ví dụ sau:

struct vector {
    int  size() const;
    bool empty() const;
};

bool vector::empty() const
{
    return size() == 0;
}

Mã lắp ráp được tạo cho vector::empty(bằng tiếng kêu, với tối ưu hóa):

push    rax
call    vector::size() const
test    eax, eax
sete    al
pop     rcx
ret

Tại sao nó phân bổ không gian ngăn xếp? Nó hoàn toàn không được sử dụng. Các pushpopcó thể được bỏ qua. Các bản dựng tối ưu của MSVC và gcc cũng sử dụng không gian ngăn xếp cho chức năng này (xem trên godbolt ), vì vậy phải có một lý do.


7
Bạn đã tính đến thistham số ngầm ?
dan04

1
@Bob__: Không. Tại sao tôi nên? vector::size()không được định nghĩa trong ví dụ để mô phỏng rằng nó không được nội tuyến.
Bác sĩ Gut

1
Vì vậy, làm thế nào một trình biên dịch có thể tối ưu hóa một cái gì đó mà nó không biết?
Bob__

1
@Bob__: Tôi nghĩ rằng việc biết việc thực hiện vector::size()không liên quan đến việc phân bổ hoặc không phân bổ khung ngăn xếp cho vector::empty(). Trong empty()đó chỉ là gọi, bất kể nó là gì.
Bác sĩ Gut

1
Chà, bạn đang gọi một hàm trả về một cái gì đó, bạn cần không gian cho điều đó (nếu bạn không biết gì hơn).
Bob__

Câu trả lời:


11

Nó phân bổ không gian ngăn xếp, vì vậy ngăn xếp được căn chỉnh 16 byte. Điều này là cần thiết, bởi vì địa chỉ trả về mất 8 byte, do đó, cần thêm một không gian 8 byte để giữ cho ngăn xếp 16 byte được căn chỉnh.

Việc căn chỉnh các khung ngăn xếp có thể được cấu hình với các đối số dòng lệnh cho một số trình biên dịch.

  • MSVC : Tài liệu nói rằng ngăn xếp luôn được căn chỉnh 16 byte. Không có đối số dòng lệnh có thể thay đổi điều này. Ví dụ godbolt cho thấy 40 byte bị trừ từ rsplúc bắt đầu hàm, điều đó có nghĩa là một cái gì đó khác cũng ảnh hưởng đến điều này.
  • clang : -mstack-alignmentTùy chọn chỉ định căn chỉnh ngăn xếp. Có vẻ như, mặc định là 16, mặc dù không được ghi lại. Nếu bạn đặt nó thành 8, phân bổ ngăn xếp ( pushpop) sẽ biến mất khỏi mã lắp ráp được tạo.
  • gcc : -mpreferred-stack-boundaryTùy chọn chỉ định căn chỉnh ngăn xếp. Nếu giá trị đã cho là N, nó có nghĩa là 2 ^ N byte căn chỉnh. Giá trị mặc định là 4, có nghĩa là 16 byte. Nếu bạn đặt nó thành 3 (tức là 8 byte), phân bổ ngăn xếp ( subaddcho rsp) sẽ biến mất khỏi mã lắp ráp được tạo.

Kiểm tra trên godbolt .


Đó là lý do tại sao các chuyên gia c ++, các chuyên gia luôn cảnh báo: đặt các thành viên struct / class theo thứ tự kích thước dài nhất / lớn nhất đến nhỏ nhất ... chỉ bằng cách này nó sẽ có hiệu quả chính xác
khóa

@geza: Cảm ơn bạn. Tôi đã làm một số nghiên cứu cho hai trình biên dịch khác, và viết nó vào câu trả lời của bạn. Bạn có thích nó không?
Bác sĩ Gut

1
@ Dr.Gut: cảm ơn, bạn đã trả lời tốt hơn và đầy đủ hơn. Lưu ý, căn chỉnh ngăn xếp thường được ghi lại trong ABI cho hệ thống (ví dụ: đối với một số hệ thống, đây là các tài liệu: github.com/hjl-tools/x86-psABI/wiki/X86-psABI ).
geza

@geza: Cảm ơn bạn.
Bác sĩ Gut
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.