2015-07-07 24 views
5

Cảnh báo [...]: Hành vi không xác định: thứ tự của các truy cập không ổn định là undefined trong bản Tuyên Bố này x.cpp xxxLý do cơ bản cho hành vi không xác định này là gì?

Tại sao dòng này là hành vi không xác định?

case 2: 
    Vdda = 3.3 * (*VREFINT_CAL)/ADC_DR->DATA; 

Trường hợp tờ khai/khởi tạo là:

volatile short const *VREFINT_CAL = (short *) 0x1FFFF7BA; 

volatile STRUCT_ADC_DR *ADC_DR = (STRUCT_ADC_DR*) 0x40012440; 

xác định bởi:

typedef struct 
{ 
    unsigned DATA   : 16; 
    unsigned    : 16; 
} STRUCT_ADC_DR; 

Có phải vì trình biên dịch là không chắc chắn về các yếu tố dễ bay hơi có thể hành động khác nhau theo thứ tự họ được truy cập? (Trường hợp gì)

Nhưng không nên đảm bảo rằng việc tính toán được thực hiện từ trái sang phải vì các toán tử có cùng mức độ ưu tiên?

+0

Bạn có chắc bạn biết những gì 'volatile' không? Và tại sao có các địa chỉ mã hóa cứng trong mã của bạn? – deviantfan

+1

Tôi nghĩ rằng điều này nên được lặp lại là "tại sao tiêu chuẩn đánh dấu rõ ràng điều này là hành vi không xác định/lý do cho nó ...", nếu không bạn sẽ chỉ nhận được "tiêu chuẩn nói như vậy" từ rất nhiều người. – OMGtechy

+6

Thứ tự đánh giá của toán hạng không xác định. – molbdnilo

Trả lời

10

volatile ngụ ý trình biên dịch là bạn đang đọc thứ gì đó không phải là địa chỉ bộ nhớ thông thường, như cổng I/O. Đối với hai lần đọc như vậy, rất có thể bạn sẽ muốn những lần đọc đó xảy ra theo một thứ tự nhất định.

Trong cả C và C++, thứ tự đánh giá của toán hạng không được xác định. Nếu nó giúp bạn, suy nghĩ của các bộ phận như một cuộc gọi chức năng:

Vdda = 3.3 * divide(*VREFINT_CAL, ADC_DR->DATA); 

Điểm hiện nay, mà cho volatile, nơi nó có khả năng rằng thứ tự là quan trọng, bạn có thể không muốn rời bỏ quyết định này để trình biên dịch . Vì vậy, nó cảnh báo về nó.

Để loại bỏ cảnh báo, chỉ cần làm cho đơn đặt hàng rõ ràng bằng cách giới thiệu các điểm chuỗi bổ sung cho mã của bạn. Ví dụ:

short const x = *VREFINT_CAL; 
unsigned const y = ADC_DR->DATA; 
Vdda = 3.3 * x/y; 
+2

Bạn đúng vậy. Tôi có thể gặp rắc rối lớn khi DATA được truy cập trước VREFINT_CAL vì nó gây ra để đặt lại giá trị. – dhein

+0

@Zaibis Vui mừng khi biết rằng cảnh báo thực sự giúp bạn bắt lỗi trong trường hợp này. – ComicSansMS

+0

@Zaibis Thật vậy, liên kết Alf báo cáo cho bạn biết chính xác rằng, khi trả lời câu hỏi "Có vấn đề gì không?": Nó phụ thuộc vào dữ liệu của bạn và cách ứng dụng của bạn xử lý nó. Trình biên dịch đang nói rằng nó * có thể * gây ra vấn đề vì công việc của nó là xa bất cứ điều gì ngoài đó. – edmz

4

Để hiểu điều này, bạn phải biết sự khác biệt giữa tự đánh giáưu tiên.

Hãy biểu hiện của bạn, ví dụ:

Vdda = 3.3 * (*VREFINT_CAL)/ADC_DR->DATA; 

Precedence (và dấu ngoặc đơn) xác định cách cây cú pháp trừu tượng (AST) được xây dựng. Kết quả sẽ giống như sau:

= 
    Vdda 
    * 
    3.3 
    /
     * 
     VREFINT_CAL 
     -> 
     ADC_DR 
     DATA 

Thứ tự đánh giá được xác định bởi sự tồn tại của các điểm chuỗi. Và mã của bạn chỉ có một điểm chuỗi, ở cuối biểu thức (;).

Vì vậy, thứ tự đánh giá của mọi biểu thức con không được chỉ định. Đó là, trình biên dịch có thể thực hiện bất kỳ phép tính trung gian và truy cập bộ nhớ theo thứ tự nào mà nó thấy phù hợp. Một số người thích nghĩ rằng các biểu thức con được đánh giá từ trái sang phải, nhưng đó không phải là cách ngôn ngữ hoạt động.

Thông thường nó sẽ không tạo ra bất kỳ sự khác biệt nào, nhưng hai trong số các biểu thức con của bạn là volatile (*VREFINT_CALADC_DR->DATA) để thứ tự quan trọng. Có lẽ nó không quan trọng với bạn, nhưng nó chắc chắn quan trọng đối với trình biên dịch.

Để giải quyết vấn đề sử dụng một số tạm thời, chỉ cần thêm một điểm chuỗi trung gian:

short a = *VREFINT_CAL; 
unsigned b = ADC_DR->DATA; 
Vdda = 3.3 * a/b; 
+0

@Zaibis: Vâng, vâng.Nhưng bạn vẫn cần một biến cục bộ: 'short a; a = * VREFINT_CAL, b = ADC_DR-> DATA, Vdda = 3,3 * a/...; '. Nếu bạn cố gắng làm: 'Vdda = 3.3 * (0, * VREFINT_CAL)/...;' điều này sẽ không hoạt động. – rodrigo

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