2013-07-22 33 views
24

Trong C++ Tôi biết các đối tượng staticglobal được xây dựng trước chức năng main. Nhưng như bạn đã biết, trong C, không có loại nào như vậy initialization procedure trước main.Khi nào các biến tĩnh và toàn cầu được khởi tạo?

Ví dụ, trong mã của tôi:

int global_int1 = 5; 
int global_int2; 
static int static_int1 = 4; 
static int static_int2; 
  • Khi là bốn biến khởi?
  • Giá trị khởi tạo như 54 được lưu trữ trong khi biên dịch ở đâu? Làm thế nào để quản lý chúng khi khởi tạo?

EDIT:
Làm rõ câu hỏi thứ 2.

  • Trong mã của tôi, tôi sử dụng 5 để khởiglobal_int1, vậy làm thế nào trình biên dịch có thể gán5 để global_int? Ví dụ: có thể trình biên dịch trước tiên lưu trữ giá trị 5 ở đâu đó (ví dụ: bảng) và nhận giá trị này khi bắt đầu khởi chạy.
  • Để "Làm thế nào để quản lý chúng khi khởi tạo?", Nó thực sự mơ hồ và bản thân tôi vẫn chưa giải thích. Đôi khi, nó không phải là dễ dàng để giải thích một câu hỏi. Hãy nhìn nó vì tôi chưa nắm được câu hỏi đầy đủ.
+0

Tất cả bốn biến của bạn đều có lớp lưu trữ tĩnh. –

+0

@KerrekSB 'Lớp lưu trữ tĩnh' liên quan đến câu hỏi của tôi như thế nào? – Zachary

+0

Lớp lưu trữ xác định hành vi khởi tạo. –

Trả lời

21

Bằng các đối tượng tĩnh và toàn cầu, tôi giả sử bạn là đối tượng có thời lượng tĩnh được xác định tại phạm vi không gian tên. Khi các đối tượng như vậy được xác định với phạm vi cục bộ, các quy tắc hơi khác nhau.

Chính thức, C++ khởi tạo các biến như vậy trong ba giai đoạn: 1. Zero, khởi 2. khởi tĩnh 3. Năng động, khởi Ngôn ngữ cũng phân biệt giữa biến mà đòi hỏi khởi động, và những đòi hỏi tĩnh khởi: tất cả các đối tượng tĩnh (đối tượng có tuổi thọ tĩnh ) được khởi tạo bằng không, sau đó các đối tượng có khởi tạo tĩnh được khởi tạo và sau đó khởi tạo động xảy ra.

Là một phép tính gần đúng đầu tiên đơn giản, khởi tạo động có nghĩa là rằng một số mã phải được thực hiện; thông thường, static khởi tạo không. Như vậy:

extern int f(); 

int g1 = 42; // static initialization 
int g2 = f(); // dynamic initialization 

approximization Một sẽ là khởi tạo tĩnh là gì C hỗ trợ (cho các biến với đời tĩnh), năng động mọi thứ khác.

Làm thế nào trình biên dịch thực hiện điều này phụ thuộc, tất nhiên, trên khởi, nhưng trên các hệ thống dựa trên đĩa, nơi thực thi được nạp vào bộ nhớ từ đĩa, các giá trị cho tĩnh khởi là một phần của hình ảnh trên đĩa, và nạp trực tiếp bởi hệ thống từ đĩa. Trên một hệ thống Unix cổ điển, các biến toàn cầu sẽ được chia thành ba "phân đoạn":

văn bản:
Mã, nạp vào một khu vực ghi được bảo vệ. Tĩnh biến với các loại `const` cũng sẽ được đặt ở đây.
dữ liệu:
Biến tĩnh với công cụ khởi tạo tĩnh.
bss:
biến tĩnh với không initializer (C và C++) hoặc với động khởi (C++). Tệp thực thi không chứa hình ảnh cho phân đoạn này và hệ thống chỉ cần đặt tất cả thành `0` trước khi bắt đầu mã của bạn.

Tôi nghi ngờ rằng nhiều hệ thống hiện đại vẫn sử dụng thứ gì đó tương tự .

EDIT:

Một nhận xét bổ sung: ở trên đề cập đến C++ 03. Đối với các chương trình hiện tại, C++ 11 có thể không thay đổi bất kỳ điều gì, nhưng thêm constexpr (có nghĩa là một số chức năng do người dùng xác định vẫn có thể khởi tạo tĩnh) và biến cục bộ, . giun.

+0

Thx James. Câu trả lời của bạn thực sự tuyệt vời. Trong đoạn cuối, bạn đã đề cập khởi tạo động nằm trong phân đoạn .bss. Tại sao? Trực giác, tôi nghĩ rằng nó phải ở trong phân đoạn .data khi nó được khởi tạo. – Zachary

+0

Để làm phiền bạn một lần nữa. Như bạn đã biết, từ bạn trả lời, tôi hiểu rõ hơn. Nhưng tôi không biết nguyên tắc đằng sau. Các quy tắc ngôn ngữ này bắt nguồn như thế nào. Bạn có thể đưa ra một số tham chiếu cho tôi không? Đây là một liên kết [Bộ lưu trữ lớp lưu trữ] (http://en.cppreference.com/w/cpp/language/storage_duration). Sau khi đọc trang này, tôi bối rối hơn. Hai mặt hàng nhỏ cần được xem xét. – Zachary

+0

@Zack Khởi động động không được thực hiện cho đến khi chương trình bắt đầu thực thi. Theo như tải thực thi là có liên quan, nó không được khởi tạo, và đó là tất cả. –

1

diễn giải từ tiêu chuẩn:

Tất cả các biến mà không có thời gian lưu trữ năng động, không có chủ đề thời gian lưu trữ địa phương, và không phải là địa phương, có thời gian lưu trữ tĩnh. Nói cách khác, tất cả các hình cầu có thời gian lưu trữ tĩnh.

Đối tượng tĩnh có khởi tạo động không nhất thiết được tạo trước câu lệnh đầu tiên trong hàm chính. Nó được thực hiện được định nghĩa là liệu các đối tượng này được tạo trước câu lệnh đầu tiên trong chính hay trước lần sử dụng đầu tiên của bất kỳ hàm hoặc biến nào được định nghĩa trong cùng một đơn vị dịch như biến tĩnh được khởi tạo.

Vì vậy, trong mã của bạn, global_int1 và static_int1 chắc chắn được khởi tạo trước câu lệnh đầu tiên trong chính vì chúng được khởi tạo tĩnh. Tuy nhiên, global_int2 và static_int2 được khởi tạo động, do đó khởi tạo của chúng được thực hiện theo quy tắc tôi đã đề cập ở trên.

Đối với điểm thứ hai của bạn, tôi không chắc mình hiểu ý của bạn là gì. Bạn có thể làm rõ?

3

Khi nào bốn biến này được khởi tạo?

Như bạn nói, điều này xảy ra trước khi khởi động chương trình, tức là trước khi bắt đầu main. C không chỉ rõ nó; trong C++, những điều này xảy ra trong giai đoạn khởi tạo tĩnh tĩnh trước các đối tượng với các nhà xây dựng phức tạp hơn hoặc các trình khởi tạo.

Giá trị khởi tạo như 5 và 4 được lưu trữ trong khi biên dịch?

Thông thường, các giá trị khác không được lưu trữ trong một phân đoạn dữ liệu trong file chương trình, trong khi giá trị zero đang ở trong một phân khúc bss mà chỉ giữ đủ bộ nhớ cho các biến. Khi chương trình bắt đầu, phân đoạn dữ liệu được tải vào bộ nhớ và phân đoạn bss được đặt thành 0. (Tất nhiên, tiêu chuẩn ngôn ngữ không chỉ định điều này, do đó trình biên dịch có thể làm điều gì khác, như tạo mã để khởi tạo từng biến trước khi chạy main).

+0

Nhiều thx. Đặc biệt cho câu hỏi thứ 2. Biến thực sự là một đơn vị bộ nhớ địa chỉ. Vì vậy, 5 chỉ được lưu trữ tại đơn vị bộ nhớ được phân bổ cho nó trong phần/phân đoạn .data. – Zachary

+0

Tôi đã giải thích nó trong bài đăng của tôi cho câu hỏi thứ 2. Mike, bạn có nghĩ rằng việc khởi tạo được thực hiện trong quá trình liên kết không? Kể từ sau khi quá trình liên kết, các phân đoạn của chương trình về cơ bản là cố định! – Zachary

12

Lời nói đầu: Từ "tĩnh" có một số lượng lớn các ý nghĩa khác nhau trong C++. Đừng bối rối.

Tất cả các đối tượng của bạn có thời gian lưu trữ tĩnh. Đó là bởi vì chúng không tự động hay động. (Cũng không phải là luồng nội bộ, mặc dù chuỗi địa phương giống như tĩnh.)

Trong C++, các đối tượng tĩnh được khởi tạo theo hai giai đoạn: khởi tạo tĩnh và khởi tạo động.

  • động khởi đòi hỏi mã thực tế để thực hiện, vì vậy điều này xảy ra cho các đối tượng bắt đầu bằng một cuộc gọi constructor, hoặc trong trường hợp khởi tạo là một biểu hiện mà chỉ có thể được đánh giá trong thời gian chạy.

  • Khởi tạo tĩnh là khi trình khởi tạo được biết là tĩnh và không có hàm khởi tạo nào cần chạy. (Khởi tạo tĩnh là không khởi tạo hoặc hằng số khởi tạo.) Đây là trường hợp cho các biến số int của bạn với bộ khởi tạo không đổi và bạn được đảm bảo rằng các biến đó thực sự được khởi tạo trong giai đoạn tĩnh.

  • (biến tĩnh-lưu trữ với khởi động là cũng zero-initialzed tĩnh trước bất cứ điều gì khác xảy ra.)

Điểm quan trọng là giai đoạn khởi tạo tĩnh doens't "chạy" tại tất cả các. Dữ liệu có ngay từ đầu. Điều đó có nghĩa là không có "thứ tự" hoặc bất kỳ thuộc tính động nào khác có liên quan đến việc khởi tạo tĩnh. Các giá trị ban đầu được mã hóa cứng vào nhị phân chương trình của bạn, nếu bạn muốn.

Các vấn đề liên quan