2012-01-14 4 views
6

Tôi đang đọc một cuốn sách mà đề cập nàyphân bổ lưu trữ cho các biến const

Nếu trình biên dịch biết mỗi sử dụng const, nó không cần phải phân bổ không gian để giữ nó. Ví dụ:

  1. const int c1=1;
  2. const int c3=my_f(3);
  3. extern const int c4;

Cho rằng giá trị của C3 và C4 không được gọi là thời gian biên dịch, lưu trữ phải được phân bổ cho C3 và C4.

Tôi không hiểu bất kỳ điều nào trong số này. Những nghi ngờ của tôi là:

Có nghĩa là gì khi giữ ở đây? Nó sẽ vẫn không cần phải lưu trữ tất cả mọi thứ trong bộ nhớ? Đối với c1, chúng tôi có phân bổ bộ nhớ không?

Hãy xóa những nghi ngờ của tôi.

Cảm ơn bạn.

+1

Điều gì đã xảy ra với 'c2'? –

Trả lời

4

c1 khác với hai hằng số khác ở chỗ nó được khởi tạo với giá trị bằng chữ. Điều này cho phép trình biên dịch đưa giá trị mà ở khắp mọi nơi hằng số được sử dụng, như thế này:

int x = z + c1; 

có thể được thay thế bằng

int x = z + 1; 

Điều này có nghĩa rằng trình biên dịch không cần phải phân bổ không gian và lưu trữ 1 trong đó.

c3c4 khác nhau: một được tính bằng cách sử dụng hàm và giá trị khác được cung cấp từ một đơn vị biên dịch khác. Điều này có nghĩa là trình biên dịch không còn có thể thực hiện thay thế theo cách có thể với c1: các giá trị của c3c4 không được biết đến với trình biên dịch. Do đó trình biên dịch tạo mã cho

int x = z + c4; 

giống như cách c4 là một biến được lưu trữ ở một nơi nào đó trong bộ nhớ. Vì trong trường hợp này c4 là hằng số bên ngoài, trình liên kết sẽ giải quyết vị trí của nó và điền vào thông tin mà trình biên dịch bị thiếu (cụ thể là địa chỉ c4) để chương trình hoàn thành và sẵn sàng chạy.

+0

Cảm ơn bạn đã trả lời nhưng điều đó có nghĩa là bất cứ khi nào một biến được định nghĩa là const và được khởi tạo bằng chữ, nó hoạt động như macro và bất cứ nơi nào trong chương trình được sử dụng justs trình biên dịch sẽ thay thế biến bằng giá trị? –

+1

@Leoheart Trình biên dịch được * cho phép * để thực hiện việc thay thế đó và hầu hết các trình biên dịch đều làm điều đó. Nhưng theo như tôi biết, các trình biên dịch không phải "nội tuyến" khai báo hằng số: tiêu chuẩn cho phép họ làm theo một trong hai cách.Hơn nữa, bạn được phép lấy một địa chỉ của một hằng số được khai báo, trong trường hợp đó trình biên dịch đặt nó vào bộ nhớ ngoài việc nội tuyến nó ở những nơi nó được sử dụng. – dasblinkenlight

+0

OK. Cảm ơn. –

1

Là một biểu thức hằng số không đổi, trình biên dịch có mọi quyền sử dụng phép gấp liên tục để loại bỏ nó khỏi chương trình. Điều này không đúng nếu bạn lấy địa chỉ của nó. Ngoài ra, một trình biên dịch tối ưu hóa hiện đại có thể sử dụng LTO, nội tuyến và gấp liên tục để làm tương tự với c3 và c4, nếu có thể.

Nếu bạn không lấy địa chỉ của một biến, trình biên dịch không có nghĩa vụ phân bổ nó nếu nó có thể tạo mã với kết quả tương đương, theo quy tắc as-if.

Chỉnh sửa: Gấp liên tục là nơi trình biên dịch đánh giá biểu thức tại thời gian biên dịch thay vì thời gian chạy. Ví dụ: bạn có thể hợp pháp làm int x[3 + 4]; trong đó 3 + 4 được đánh giá tại thời điểm biên dịch. Một số ví dụ, đặc biệt là những người có liên quan đến ICE, là tiêu chuẩn bắt buộc, nhưng việc thực hiện có thể thực hiện nhiều hơn nếu có thể. LTO là Tối ưu hóa thời gian liên kết, là nơi trình biên dịch thực hiện tối ưu hóa trên các đơn vị dịch khi chúng được liên kết với nhau. Điều này có nghĩa là trình biên dịch có thể inline nội dung của my_f, và sau đó (tùy thuộc vào cơ thể) liên tục gấp nó ra để làm cho c3 một biểu thức liên tục, và sau đó liên tục gấp nó vào bất cứ nơi nào nó được sử dụng và không phân bổ nó. Đối với c4, LTO có thể mang lại giá trị là c4 như một biểu thức không đổi, trong trường hợp này, nó có thể được gấp và xóa liên tục.

Trong C++ 11 có constexpr chức năng cho phép nhiều việc khác được thực hiện trong khu vực này.

+0

Tôi rất tiếc, tôi cũng không thể hiểu câu trả lời của bạn. những gì là liên tục gấp và LTO? –

+0

OK. Cảm ơn. –

+0

Một câu hỏi cuối cùng: điều đó có nghĩa là bất cứ khi nào một biến được định nghĩa là một const và được khởi tạo với một chữ, nó hoạt động như một macro và bất cứ nơi nào trong chương trình được sử dụng justs trình biên dịch thay thế biến với giá trị? –

2

Const có 2 lần sử dụng - thay thế cho macro (biểu thức không đổi) và cũng là dữ liệu không thay đổi.

Tuyên bố này:

const int c1=1; 

về cơ bản là một phiên bản kiểu an về điều này:

#define c1 1 

như vậy mà mã này:

int foo = c1; 

chỉ đơn giản có thể được biên dịch như:

int foo = 1; 

Cách nào hiệu quả hơn.

Mặt khác, điều này:

const int c3=my_f(3); 

đang được sử dụng như một c3 không thay đổi. Nó có thể tồn tại trong bộ nhớ, nhưng bạn không thể sửa đổi nó. Về bản chất, đây là phiên bản an toàn hơn của int c3=my_f(3);.

Để minh họa điều này:

int a1[c1]; 
int a2[c3]; 

a1 là hợp lệ, như trình biên dịch có thể suy ra a1 là một biểu hiện thường xuyên. a2 là không, vì trong khi c3 là const, nó có thể không được biết tại thời gian biên dịch.

C++ 11 thêm từ khóa constexpr tương tự như const, mặc dù nghiêm ngặt hơn const. Chỉ c1c2 có thể là constexpr. c3 cũng có thể được, mặc dù nó sẽ yêu cầu rằng my_f là quá.