Tại sao sách nói, trình biên dịch phân bổ không gian cho các biến trong bộ nhớ?


18

Tại sao sách nói, "trình biên dịch phân bổ không gian cho các biến trong bộ nhớ". Nó không phải là thực thi mà làm điều đó? Ý tôi là, ví dụ, nếu tôi viết chương trình sau đây,

#include <iostream>
using namespace std;

int main()
{
   int foo;
   return 0;
}

và biên dịch nó, và có được một tệp thực thi (hãy để nó là chương trình.exe), bây giờ, nếu tôi chạy chương trình.exe, tệp thực thi này sẽ tự ra lệnh phân bổ một số không gian cho biến foo. Phải không? Vui lòng giải thích lý do tại sao sách tiếp tục nói, "trình biên dịch sẽ làm điều này ... làm điều đó".


11
bạn đang nói về những cuốn sách nào?
wirrbel

4
"Câu hỏi liên quan" của bạn nên là một câu hỏi riêng biệt.
SShaheen

Câu sizeofhỏi bây giờ được đặt tại Tại sao sizeof được gọi là toán tử thời gian biên dịch?

Trình biên dịch tạo mã thực hiện điều này hoặc đó là những gì họ đang nói. trực tiếp hay gián tiếp.
old_timer

FYI stackoverflow.com/questions/7372024/... và lưu ý rằng một trình biên dịch có thể quyết định thay đổi vị trí một biến nhận thức trong bộ nhớ vì lợi ích của sự liên kết ví dụ: stackoverflow.com/questions/17774276/...
NoChance

Câu trả lời:


20

Bạn đúng rằng trình biên dịch như vậy sẽ biến mất khi chương trình của bạn thực sự chạy. Và nếu nó chạy trên một máy khác, trình biên dịch sẽ không còn khả dụng nữa.

Tôi đoán điều này là để phân biệt rõ ràng giữa bộ nhớ thực sự được phân bổ bởi mã của riêng bạn. Trình biên dịch sẽ chèn một số mã trong chương trình của bạn để cấp phát bộ nhớ (như sử dụng các lệnh mới, malloc hoặc các lệnh tương tự).

Vì vậy, sách sử dụng "trình biên dịch thực hiện điều này hoặc điều đó" thường để nói rằng trình biên dịch đã thêm một số mã không được đề cập rõ ràng trong các tệp mã của bạn. Đúng như vậy, đây không phải là chính xác những gì đang xảy ra. Từ quan điểm này, rất nhiều điều được đề cập trong hướng dẫn sẽ sai nhưng sẽ cần những giải thích khá công phu.


Vâng, đó là những gì tôi tin. Cảm ơn cho một câu trả lời nhanh chóng!
Bộ giải mã hòa bình

12
trình biên dịch phân bổ cho biến foo trên ngăn xếp bằng cách thay thế nó bằng một phần bù cho con trỏ ngăn xếp trong quá trình biên dịch. Nó hoàn toàn không liên quan đến phân bổ heap được thực hiện bởi mallocet. al.
wirrbel

@holger: Bạn phản đối là đúng về mặt kỹ thuật. Nhưng không gian ngăn xếp như vậy vẫn phải được phân bổ khi chương trình bắt đầu trước khi có thể được sử dụng (điều này có thể xảy ra theo nhiều cách khác nhau, đôi khi tùy thuộc vào kiến ​​trúc CPU). Tôi đã cố gắng tìm một số chi tiết làm thế nào điều này xảy ra nhưng không có nhiều thành công.
thorsten müller

2
Tôi nghĩ kích thước ngăn xếp cho luồng chính được dành riêng bởi trình liên kết và sau đó được xử lý bởi HĐH. Đối với các luồng tùy chỉnh, nó tương tự như phân bổ heap tức là người gọi có thể sửa kích thước khi chạy.
wirrbel

4

Nó phụ thuộc vào biến. HĐH phân bổ heap, chương trình sẽ phân bổ stack và trình biên dịch sẽ phân bổ không gian cho toàn cầu / statics, tức là chúng được tích hợp vào exe. Nếu bạn phân bổ 1MB bộ nhớ chung, kích thước exe của bạn sẽ tăng ít nhất 1 MB


1
Đó không phải là câu hỏi này.
Philipp

2
thực ra nó gần với câu hỏi hơn các câu trả lời khác được liệt kê ở đây.
wirrbel

@James Ah, đây không phải là kinh nghiệm của tôi. Ví dụ, int test[256][1024]; int main(){ test[0][0]=2; return 0; } chương trình nhỏ này có 1 MB được phân bổ nhưng chỉ tạo cho tôi tệp đối tượng 1,4 Kb và tệp thực thi 8.4 Kb. Nó nên sử dụng đúng dung lượng RAM.
Garet Claborn

1
Không phải nó chỉ là các lệnh phân bổ được lưu trữ cho toàn cầu sao? Nếu bạn đã mã hóa tất cả các giá trị bằng cách sử dụng các nguyên hàm như int hoặc char, kích thước của tệp thực thi chắc chắn sẽ tăng hơn nhiều so với số lượng biến được thêm vào. Chẳng hạn như int a1=1,a2=2,... tất cả các cách để ... , a1048576=1048576;Chỉ sau đó bạn chắc chắn sẽ nhận được một cái gì đó lớn hơn 1mb tôi nghĩ.
Garet Claborn

2
Đó là bất cứ điều gì đưa dữ liệu vào phần BSS của exe
James

4

những gì trình biên dịch sẽ làm là lấy mã của bạn và biên dịch nó thành mã máy. Những gì bạn đề cập là một ví dụ tốt trong đó một trình biên dịch chỉ cần dịch.

Chẳng hạn, khi bạn viết

int foo;

Bạn có thể xem như 'Tôi đang nói với trình biên dịch [ trong đầu ra mà nó tạo ra ] yêu cầu máy tính dự trữ đủ ram cho một int mà tôi có thể tham chiếu sau Trình biên dịch có thể sẽ sử dụng id tài nguyên hoặc một số cơ chế để theo dõi foo trong Mã máy, bạn có thể sử dụng foo trong một tệp văn bản thay vì viết lắp ráp! Thắng lợi !

Vì vậy, bạn cũng có thể xem xét điều này khi trình biên dịch đang viết một lá thư ( hoặc có thể là một cuốn tiểu thuyết / bách khoa toàn thư ) cho tất cả các bộ xử lý và thiết bị được nhắm mục tiêu. Bức thư được viết bằng tín hiệu nhị phân (nói chung) có thể được dịch sang các bộ xử lý khác nhau bằng cách thay đổi mục tiêu. Bất kỳ 'thư' và / hoặc kết hợp nào cũng có thể gửi tất cả các loại yêu cầu và / hoặc dữ liệu - như xin vui lòng phân bổ không gian cho biến này mà lập trình viên đã sử dụng.


3

Nói "trình biên dịch phân bổ bộ nhớ" có thể không thực sự chính xác theo nghĩa đen, nhưng đó là một phép ẩn dụ gợi ý theo cách đúng đắn.

Điều thực sự xảy ra là trình biên dịch tạo ra một chương trình phân bổ bộ nhớ của chính nó. Ngoại trừ việc đó không phải là chương trình phân bổ bộ nhớ, mà là HĐH.

Vì vậy, những gì thực sự xảy ra là trình biên dịch tạo ra một chương trình mô tả các yêu cầu bộ nhớ của nó và HĐH lấy mô tả đó và sử dụng nó để phân bổ bộ nhớ. Ngoại trừ việc HĐH là một chương trình và các chương trình không thực sự làm gì cả, chúng mô tả một tính toán được thực hiện bởi CPU. Ngoại trừ việc CPU thực sự chỉ là một mạch điện tử phức tạp, không phải là một homonculus nhỏ được nhân hóa.

Nhưng thật hợp lý khi nghĩ về các chương trình và trình biên dịch và CPU như những người nhỏ bé sống trong máy tính, không phải vì chúng thực sự là, mà bởi vì đó là một phép ẩn dụ rất phù hợp với bộ não con người.

Một số phép ẩn dụ hoạt động tốt để mô tả mọi thứ ở một mức độ trừu tượng, nhưng không hoạt động tốt ở cấp độ khác. Nếu bạn nghĩ về cấp độ của trình biên dịch, sẽ rất hợp lý khi mô tả hành động tạo mã sẽ dẫn đến việc bộ nhớ được cấp phát khi chương trình đang được biên dịch thực sự chạy dưới dạng "cấp phát bộ nhớ". Nó đủ gần để khi chúng ta nghĩ về cách trình biên dịch hoạt động, chúng ta có ý tưởng đúng và không quá dài đến nỗi chúng ta quên mất những gì chúng ta đang làm. Nếu chúng ta cố gắng sử dụng phép ẩn dụ đó ở cấp độ của chương trình được biên dịch đang chạy, nó sẽ gây hiểu lầm theo một cách kỳ lạ, đó là những gì bạn nhận thấy.


0

Trình biên dịch là người quyết định nơi lưu trữ một biến - có thể trong ngăn xếp hoặc đăng ký miễn phí. Dù quyết định lưu trữ được đưa ra bởi trình biên dịch, mã máy tương ứng để truy cập biến đó sẽ được tạo và không thể thay đổi trong thời gian chạy. Theo nghĩa này, trình biên dịch chịu trách nhiệm phân bổ không gian cho các biến và chương trình cuối cùng chỉ hoạt động mù quáng như một thây ma trong thời gian chạy.

Bây giờ, đừng nhầm lẫn điều này với quản lý bộ nhớ động khác nhau như malloc, mới hoặc có thể là quản lý bộ nhớ của riêng bạn. Trình biên dịch đang xử lý lưu trữ và truy cập biến đổi nhưng không quan tâm giá trị thực có nghĩa là gì trong một khung / thư viện khác. Ví dụ:

byte* pointer = (byte*)malloc(...);

Trong thời gian chạy, malloc có thể trả về một số tùy ý nhưng trình biên dịch không quan tâm, tất cả những gì nó quan tâm là nơi lưu trữ số đó.


0

Một cụm từ chính xác hơn sẽ là: - "trình biên dịch báo cho trình tải dự trữ không gian cho các biến"

Trong môi trường C-ish sẽ có ba loại không gian cho các biến: -

  • một khối cố định cho các biến tĩnh
  • Một khối lớn cho các biến "tự động" thường được gọi là "ngăn xếp". Các chức năng lấy một đoạn khi nhập cảnh và giải phóng nó khi trở về.
  • Một khối lớn được gọi là "heap", nơi phân bổ bộ nhớ được quản lý chương trình (sử dụng malloc () hoặc API quản lý bộ nhớ tương tự.

Trên một bộ nhớ heap OS hiện đại sẽ không thực sự được bảo lưu mà được phân bổ theo yêu cầu.


0

Có, bạn đã đúng, trong trường hợp này (khai báo một biến trong hàm), câu trong sách của bạn có thể không chính xác: khi bạn khai báo một biến trong hàm, nó sẽ được phân bổ trên ngăn xếp khi vào hàm. Dù sao, một trình biên dịch nên tối ưu hóa tình huống: nếu hàm không đệ quy ( main()là một ứng cử viên tốt cho nó), thì bạn có thể "phân bổ" thời gian biên dịch (trên BSS).

. tĩnh, động, được phân bổ, malloc()v.v. và hiển thị địa chỉ của chúng (sử dụng trình %Xđịnh dạng printf()để dễ đọc hơn). Các biến nằm trong ngăn xếp sẽ có địa chỉ bộ nhớ rất khác nhau.)


0

Điều duy nhất được thực hiện trong thời gian chạy sẽ trả cho poinbter stack một số tiền nhất định. Vì vậy, trình biên dịch quyết định trước:

  • bao nhiêu không gian ngăn xếp sẽ cần thiết cho chức năng.
  • Tại điểm bù từ con trỏ ngăn xếp, mỗi biến riêng lẻ sẽ được định vị.

Cái này có thể được gọi là "cấp phát", nhưng tất nhiên, trong thời gian biên dịch, nó chỉ đặt trong mô hình mà trình biên dịch có của chương trình đang chạy.

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.