2010-10-02 45 views
7
int x = 2; 
volatile int y = 2; 

const int z = x/y; 

int main(){ 
    int x = 2 + 3; 

    double d = 7/3; 
} 

Tôi có ba câu hỏi ở đây:nhầm lẫn dễ bay hơi và đôi

Thứ nhất, trình biên dịch có thể tính toán giá trị của 'z' tại thời gian biên dịch là 1 trong trường hợp này?

Thứ hai, tôi quan sát thấy trình biên dịch không tạo ra hướng dẫn lắp ráp để thêm 2 và 3 để khởi tạo x. Nó trực tiếp khởi tạo x với 5. Có thể thực hiện tương tự với 'd' không?

Thứ ba, Có cuốn sách hay nào để đọc về hai khái niệm này không? Bất kỳ trích dẫn nào từ Tiêu chuẩn sẽ hữu ích (Tài liệu chuẩn dường như là một địa điểm thú vị mặc dù rất đáng sợ)

+1

Vì bạn đã làm nó cho x, tại sao bạn không kiểm tra những gì các hướng dẫn lắp ráp cho d = 7/3? –

+0

@Emile Cormier: Nó liên quan đến lệnh fld và fstp. Tôi không thể hiểu nhiều, mặc dù tôi vẫn chưa từ bỏ – Nivhus

+0

Btw, trong mã này d == 2, đó là phân chia số nguyên. – ybungalobill

Trả lời

4

Thứ nhất, trình biên dịch có thể tính giá trị của 'z' tại thời gian biên dịch thành 1 trong trường hợp này ?

Không đọc hoặc ghi vào biến dễ bay hơi được coi là có tác dụng phụ, do đó trình biên dịch không được phép thực hiện việc này.

Thứ hai, tôi quan sát thấy trình biên dịch không tạo ra hướng dẫn lắp ráp để thêm 2 và 3 để khởi tạo x. Nó trực tiếp khởi tạo x với 5. Có thể thực hiện tương tự với 'd' không?

Có. Miễn là trình biên dịch có thể chứng minh rằng không có tác dụng phụ. Ví dụ. nếu tràn hoặc phân chia bằng không xảy ra trong quá trình tính toán, nó không thể tính toán nó tại thời gian biên dịch kể từ khi tính toán sẽ kích hoạt một ngoại lệ CPU khi chạy.

Thứ ba, Có cuốn sách hay nào để đọc về hai khái niệm này không?

Có. Tiêu chuẩn ISO C++ mô tả chính xác những gì bạn đang yêu cầu. Sách là tốt để tìm hiểu những điều cơ bản hoặc lý thuyết. Nó không có ý nghĩa bằng văn bản sách mà rephrase tất cả các chi tiết kỹ thuật được mô tả trong tiêu chuẩn.

+0

Dù sao, tiêu chuẩn chỉ mô tả các kết quả bạn sẽ có, và không phải là tối ưu hóa có thể hoặc nên trình biên dịch làm. – ruslik

+0

Cảm ơn. Nghi ngờ của tôi chính là điều này. Nếu trình biên dịch có thể tính toán tĩnh giá trị của 7/3, thì nó đại diện cho kết quả dấu chấm động trong định dạng nào? Là nó bắt buộc IEEE754? – Nivhus

+0

@Nivhus Tôi nghĩ nó phụ thuộc vào nền tảng. Nó chỉ được bảo đảm rằng trên nền tảng này giá trị này sẽ được hiểu là 7/3. – ruslik

1

Đối với "đầu tiên" - y phải được truy cập, khi z được khởi tạo, nhưng tôi không nghĩ rằng kết quả của việc tiếp cận này phải được sử dụng để tính toán z, nếu thực hiện bằng cách nào đó biết rằng nó phải là 2. Đối với chương trình này có (tôi nghĩ) chỉ có 2 cách có thể có bất kỳ giá trị nào khác:

  1. nó được sửa đổi bởi trình gỡ rối hoặc sự can thiệp khác với chương trình.
  2. bộ nạp đặt các hình cầu dễ bay hơi ở một số vùng bộ nhớ không hoạt động như bộ nhớ thông thường trên phần cứng của bạn. (trong trường hợp này thực sự là hành vi được xác định rất kỳ quặc, đến mức tôi không nghĩ nó hợp pháp đối với mã như đã viết, nhưng nó có liên quan nếu chương trình, hoặc một phần nào đó của quá trình xây dựng bên ngoài chương trình, có thể bằng cách nào đó kiểm soát nơi đối tượng kết thúc).

Cả hai điều đó là việc thực hiện có thể loại trừ - trong trường hợp thứ hai bằng cách biết cách trình nạp hoạt động, ngay từ đầu bằng cách đặt giới hạn cho những gì bạn có thể đạt được với trình gỡ lỗi ("viết dễ bay hơi biến kết quả trong hành vi đáng ngạc nhiên "). Thất vọng cho người dùng của trình gỡ rối, nhưng tiêu chuẩn không hạn chế cách các trình gỡ rối hoạt động, hoặc bộ nhớ "thực sự" có chứa gì, nó chỉ hạn chế những triển khai và chương trình C++ hợp lệ, và những gì C++ "thấy".

Trong thực tế, bạn nghĩ rằng trình biên dịch sẽ không bận tâm xử lý một đối tượng dễ bay hơi như tùy thuộc vào tối ưu hóa. Đó là một đối tượng không phải const, và bạn phải nghi ngờ rằng lý do duy nhất để định nghĩa một đối tượng dễ bay hơi không phải là const vì nó sẽ thay đổi theo cách mà trình biên dịch không mong đợi [*]. Bạn hy vọng nó sẽ chỉ đọc y và làm việc phân chia, nhưng tôi nghĩ một trường hợp có thể được thực hiện để tối ưu hóa là hợp pháp. Đối với "thứ hai" - trong trường hợp chương trình của bạn, trình biên dịch có thể khởi tạo d với giá trị được tính trước theo quy tắc "as-if", miễn là nó biết phân chia giá trị nào tạo ra. Đối với vấn đề đó trong chương trình của bạn, nó có thể xóa hoàn toàn d.

"Miễn là phân chia giá trị sản xuất" phụ thuộc vào việc thực hiện - nếu nó hỗ trợ thay đổi chế độ làm tròn IEEE hoặc tương đương, và nếu nó không biết chế độ nào sẽ có hiệu lực, biết trước kết quả của số học đơn giản.

Quy tắc "as-if" bao gồm 85% tối ưu hóa trình biên dịch. Nó được đề cập trong phần 1.9 của tiêu chuẩn, đáng xem. Tôi đồng ý rằng tài liệu nói chung là khá đáng sợ và ngôn ngữ sử dụng đôi khi không thể hiểu được, nhưng bạn phải bắt đầu từ đâu đó, vì vậy hãy bắt đầu với bất kỳ điều gì bạn quan tâm ;-)

[*] Cụ thể, và đây không phải là điều được đề cập trong tiêu chuẩn C++ 03 theo bất kỳ cách nào, một số trình biên dịch (Microsoft) liên quan đến volatile trong định nghĩa của chúng về ngữ nghĩa luồng.

+0

Cảm ơn. Vì vậy, tôi hiểu rằng trừ khi trình biên dịch có thể chứng minh (bằng cách nào đó) rằng y không phải là 2 tại thời gian khởi tạo thư viện, trình biên dịch chắc chắn sẽ đọc y để khởi tạo z. Ngay cả khi nó không, nó vẫn là một hành vi phù hợp. Đúng không? – Nivhus

+0

Trong ví dụ của tôi, giả sử 'd' không được loại bỏ hoàn toàn, nghi ngờ của tôi vẫn còn nếu giá trị của 7/3 sẽ được tính theo chuẩn IEEE754? Điều gì xảy ra nếu kiến ​​trúc đích không hỗ trợ IEEE754?Tôi nghĩ rằng vấn đề này không giữ cho số học đơn giản ví dụ (2 + 3) mà sẽ được phổ quát trên tất cả các nền tảng. – Nivhus

+0

Nó chắc chắn sẽ đọc y nếu nó không thể chứng minh rằng nó * là * 2. Những gì tôi không chắc chắn, là chính xác những gì hoàn cảnh nó sẽ có thể chứng minh rằng nó là 2. Nếu nó muốn hỗ trợ giá trị được thay đổi bởi một trình gỡ lỗi tại một điểm rất sớm của chương trình khởi tạo, sau đó tất nhiên nó không thể chứng minh điều đó. Nếu nó muốn hỗ trợ 'y' được đặt tại một địa chỉ ma thuật mà đọc một số cổng đầu vào, nó không thể chứng minh điều đó. Nhưng tôi nghĩ rằng bạn có thể viết một cách hợp pháp C++ trong đó 'volatile' không làm gì cả, mặc dù 1.9/6, nếu bạn biết rằng, đọc/ghi vào bộ nhớ không phải là" quan sát "* trên phần cứng này *. –

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