Việc khai báo một biến động có nghĩa là gì?


9

Nhiều chương trình cấp thấp sử dụng từ khóa dễ bay hơi cho các loại để ánh xạ bộ nhớ và như vậy, tuy nhiên tôi hơi bối rối về những gì nó THỰC SỰ làm trong nền. Nói cách khác, điều đó có nghĩa là gì khi trình biên dịch không "tối ưu hóa" địa chỉ bộ nhớ?


1
Nếu bạn đang đọc tuổi của mình trong một volatilebiến số và nó báo là 5 và bạn sẽ đọc lại vào năm tới, bạn sẽ được đảm bảo nhận được 6.
5gon12eder

@ 5gon12eder, tôi hiểu sự biến động có nghĩa là một cái gì đó có thể thay đổi nhanh chóng và dễ dàng, nhưng nó hoạt động như thế nào? : S
Vikaton

Ngoài ra, tùy thuộc vào các cờ biên dịch của bạn, một biến không biến động 'có thể' hiển thị trong trình gỡ lỗi của bạn (ví dụ: bạn đang sử dụng mã C + Eclipse + gdb), như: 'tối ưu hóa giá trị' vì giá trị của biến hiện tại một nơi nào đó trong một đăng ký. Nếu bạn không biết cách sử dụng các công cụ / tính năng gỡ lỗi ngôn ngữ lắp ráp, chỉ cần khai báo biến của bạn bằng cách sử dụng công cụ sửa đổi dễ bay hơi.

Câu trả lời:


11

volatile có nghĩa là một số bộ xử lý hoặc thiết bị I / O khác hoặc một cái gì đó có thể thay đổi biến từ bên dưới bạn.

Với một biến thông thường, các bước trong chương trình của bạn là điều duy nhất sẽ thay đổi nó. Vì vậy, ví dụ nếu bạn đọc 5từ một biến và bạn không thay đổi nó, nó vẫn sẽ chứa 5. Vì bạn có thể dựa vào điều đó, chương trình của bạn không phải mất thời gian để đọc lại biến lần sau khi bạn muốn sử dụng nó. Trình biên dịch C ++ rất thông minh để tạo mã chỉ cần nhớ 5.

Nhưng bạn có thể đọc nó 5, sau đó có lẽ hệ thống tải dữ liệu từ đĩa vào bộ nhớ đó, thay đổi nó thành 500. Nếu bạn muốn chương trình của bạn đọc giá trị mới 500, bạn cần trình biên dịch không quá thông minh về việc sử dụng đọc trước đó 5. Bạn cần nói với nó để tải lại giá trị mỗi lần. Đó là những gì volatile.

Một sự tương tự cho trẻ 5 tuổi
Giả sử bạn đặt một tờ giấy lớn trên bàn. Ở một góc của tờ giấy, bạn ghi lại số điểm hiện tại của một trò chơi đang diễn ra , 3 to 4. Sau đó, bạn đi đến phía đối diện của bàn và bắt đầu viết một câu chuyện về trò chơi. Bạn của bạn đang xem trò chơi cập nhật điểm số ở góc đó khi trò chơi tiếp tục. Cô xóa 3 to 4và viết 3 to 5.

Khi bạn đặt điểm số trò chơi vào câu chuyện của mình, bạn có thể:

  1. Viết số điểm cuối cùng bạn đọc, 3 to 4vui vẻ cho rằng nó không thay đổi (hoặc không bận tâm nếu nó đã làm), hoặc
  2. Đi bộ về phía đối diện của bảng để đọc điểm hiện tại (điều xảy ra là 3 to 5bây giờ) và đi bộ trở lại. Đó là cách một volatilebiến hoạt động.

11

volatile có nghĩa là hai điều:

  1. Giá trị của biến có thể thay đổi mà không cần bất kỳ mã nào của bạn thay đổi. Do đó, bất cứ khi nào trình biên dịch đọc giá trị của biến, nó có thể không cho rằng nó giống với lần đọc trước hoặc nó giống với giá trị cuối cùng được lưu trữ, nhưng nó phải được đọc lại.

  2. Hành động lưu trữ giá trị cho biến dễ bay hơi là "tác dụng phụ" có thể được quan sát từ bên ngoài, do đó trình biên dịch không được phép loại bỏ hành động lưu trữ giá trị; ví dụ: nếu hai giá trị được lưu trữ trong một hàng, thì trình biên dịch thực sự phải lưu trữ giá trị hai lần.

Ví dụ:

i = 2; 
i = i; 

Trình biên dịch phải lưu trữ số hai, đọc biến i, lưu trữ biến mà nó đọc vào i.

Có một tình huống khác: Nếu một hàm sử dụng setjmpvà sau đó longjmpđược gọi, tất cả các biến cục bộ dễ bay hơi của hàm được đảm bảo có giá trị cuối cùng được lưu trữ - đây không phải là trường hợp với các biến cục bộ không biến động.


Có một số vấn đề tinh tế ở đây. Một vấn đề tinh tế là bạn đã mô tả các lần đọc dễ bay hơi là một đặc điểm của biến khi thực tế chúng là một đặc điểm về cách truy cập của biến . Nếu chúng ta có biến ivà giá trị pi = &i, thì x = *piđọc từ đó i, nhưng đọc đó không được đảm bảo có ngữ nghĩa dễ bay hơi.
Eric Lippert

1
@EricLippert: Nếu iđược khai báo là volatile int ithì piphải khai báo là volatile int *pi, trong trường hợp nào *pilà truy cập dễ bay hơi, không?
Jon Purdy

2

Giải thích trừu tượng
Cả C và C ++ đều có khái niệm về một cỗ máy trừu tượng . Khi mã sử dụng giá trị của một số biến, máy trừu tượng cho biết việc thực hiện phải truy cập giá trị của biến đó. Mã của biểu mẫu statement_A; statement_B; statement_C;phải được thực hiện theo đúng thứ tự được chỉ định. Các biểu thức chung cho ba câu lệnh đó phải được tính lại mỗi lần chúng xuất hiện.

Theo các máy trừu tượng, được đưa ra chuỗi các câu lệnh statement_A; statement_B; statement_C;, việc thực hiện trước tiên phải thực hiện statement_Atoàn bộ, sau đó statement_Bvà cuối cùng statement_C. Việc thực hiện không thể nhớ rằng bạn đã gán agegiá trị là 5. Mỗi câu lệnh tham chiếu agephải thay vào đó truy cập giá trị của biến đó.

Sẽ không cần volatiletừ khóa nếu việc triển khai thực hiện nghiêm ngặt mã C hoặc C ++ theo các thông số kỹ thuật của máy trừu tượng. Các máy trừu tượng C và C ++ không có khái niệm về các thanh ghi, không có khái niệm về các biểu hiện con chung và thứ tự thực hiện là nghiêm ngặt.

Cả hai ngôn ngữ cũng có quy tắc as-if . Việc triển khai tuân thủ tiêu chuẩn miễn là việc triển khai đó hoạt động như thể nó đã thực hiện mọi thứ theo đặc tả máy trừu tượng. Trình biên dịch có thể giả sử các biến không biến động không thay đổi giá trị giữa các bài tập. Chừng nào nó không phá vỡ as-ifquy tắc, trình tự statement_A; statement_B; statement_C;có thể được thực hiện bằng cách thực thi một phần statement_C, sau đó là một phần statement_A, sau statement_Bđó là phần còn lại statement_Avà cuối cùng là phần còn lại statement_C.

Những quy tắc như nếu không áp dụng cho volatilecác biến. Liên quan đến volatilecác biến và chức năng, việc triển khai phải thực hiện chính xác những gì bạn đã bảo nó thực hiện và chính xác theo thứ tự bạn đã bảo nó thực hiện.

Có một nhược điểm của đặc tả máy trừu tượng: Nó chậm. Một khía cạnh tích cực của C và C ++ so với các ngôn ngữ khác là chúng khá nhanh. Điều này sẽ không xảy ra nếu mã được thực thi trên các máy trừu tượng này. Các as-nếu quy định là những gì cho phép C và C ++ để được như vậy nhanh.

Câu trả lời ELI5

Điều đó có nghĩa là gì khi trình biên dịch không "tối ưu hóa" địa chỉ bộ nhớ?

"Tối ưu hóa đi" một địa chỉ bộ nhớ là một khái niệm tiên tiến, một cái gì đó không nằm trong khả năng của một đứa trẻ năm tuổi. Trẻ năm tuổi tuân thủ sẽ làm chính xác những gì bạn bảo chúng làm, không hơn, không kém. Với volatile, bạn đang nói với việc thực hiện hành động như năm: Không suy nghĩ, không tối ưu hóa ưa thích. Thay vào đó, việc thực hiện phải thực hiện chính xác những gì mã bảo nó làm.


1

(không-) dễ bay hơi là một gợi ý cho trình biên dịch cách tối ưu hóa mã (từ quan điểm mã lắp ráp được tạo):

  • không dễ bay hơi có nghĩa là trình biên dịch hiện tại của bạn quyết định vị trí của biến đó hoặc giá trị của biến s được chuyển sang chương trình con như thế nào
    • trong một địa chỉ bộ nhớ cố định,
    • trên ngăn xếp [liên quan đến stackpulum hiện tại của bộ xử lý],
    • trên heap [liên quan đến cơ sở hiện tại của bộ xử lý],
    • trong một thanh ghi bộ xử lý,
    • ...
  • dễ bay hơi có nghĩa là trình biên dịch không thể tối ưu hóa biến vì một cái gì khác bên ngoài các trình điều khiển chính-cpu-s (tức là một bộ xử lý io riêng biệt) có thể thay đổi giá trị này.

0

Các câu trả lời có vẻ khá nhất quán nhưng thiếu một điểm quan trọng. Bạn đang nói với trình biên dịch rằng bạn muốn phân bổ không gian và cho mỗi lần truy cập, hãy đọc HOẶC VIẾT, bạn muốn nó thực hiện quyền truy cập đó. Chúng tôi không muốn nó tối ưu hóa những truy cập đó hoặc biến đó vì một số lý do.

Vâng, một lý do là bởi vì người khác có thể thay đổi giá trị đó cho chúng tôi. Một lý do khác là chúng ta có thể thay đổi giá trị đó cho người khác. Rằng ai đó khác là người thay đổi nó cho chúng ta hoặc người mà chúng ta đang thay đổi nó có thể là phần cứng / logic hoặc phần mềm. Nó thường được sử dụng để xác định truy cập vào các thanh ghi điều khiển và trạng thái trong các chương trình nhúng kim loại trần, viết hoặc đọc từ phần cứng. Cũng như phần mềm nói chuyện với phần mềm giải thích trong các câu trả lời khác.

Bạn cũng sẽ thấy biến động được sử dụng để kiểm soát thời gian và thứ tự các truy cập xảy ra theo thứ tự nào, nếu bạn đang cố gắng đặt thời gian cho một phần của mã và bạn không sử dụng biến động trong câu hỏi (thời gian bắt đầu, thời gian kết thúc và sự khác biệt) chỉ cần là Tính toán gần cuối trình biên dịch có thể tự do di chuyển một trong các phép đo thời gian xung quanh (không phải nơi chúng tôi đặt chúng), không phải là nó không thể biến động nhưng kinh nghiệm cho thấy nó ít có khả năng hơn.

Thỉnh thoảng, bạn sẽ thấy nó chỉ đơn giản là đốt thời gian, một đèn led cơ bản, thế giới chào của kim loại trần, có thể sử dụng một chất dễ bay hơi cho một biến số đếm một số lượng lớn chỉ để đốt thời gian để mắt người nhìn thấy đèn led thay đổi trạng thái. Các ví dụ nâng cao hơn sau đó sử dụng bộ hẹn giờ hoặc các sự kiện khác để ghi thời gian.

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.