2013-04-16 24 views
5

GCC 4.8.0 biên dịch trong/cho 32 bit.Hành vi truyền có thể không nhất quán

tôi thấy hành vi của các trường hợp và để gây nhầm lẫn:

int16_t s16 = 0; 
double dbl = 0.0; 

s16 = (int16_t)((double)32767.0); // 1: s16 = 32767 
s16 = (int16_t)((double)32768.0); // 2: s16 = 32767 
s16 = (int16_t)((double)-32768.0); // 3: s16 = -32768 
s16 = (int16_t)((double)-32769.0); // 4: s16 = -32768 

dbl = 32767.0; 
s16 = (int16_t)dbl; // 5: s16 = 32767 
dbl = 32768.0; 
s16 = (int16_t)dbl; // 6: s16 = -32768 
dbl = -32768.0; 
s16 = (int16_t)dbl; // 7: s16 = -32768 
dbl = -32769.0; 
s16 = (int16_t)dbl; // 8: s16 = -32768 

Tôi nhận ra đó là thực hiện được xác định, nhưng quán vẫn sẽ được tốt đẹp. Bất cứ ai có thể giải thích những gì đang xảy ra?

+2

Không cần phải bỏ '32767.0',' 32768.0', '-32768.0' thành' double', chúng đã thuộc loại 'double'. – ouah

+0

@ouah Vâng, tôi biết. Tôi đã làm như vậy để nhấn mạnh hành vi. – Ioan

Trả lời

3

Các hành vi không phải là thực hiện xác định, đó là không xác định, mỗi 6.3.1.4 (1):

Nếu giá trị của các phần không thể thiếu không thể được đại diện bởi các loại nguyên, hành vi này là không xác định. 61)

61) Các remaindering hoạt động thực hiện khi một giá trị kiểu số nguyên được chuyển thành kiểu unsigned không cần phải được thực hiện khi một giá trị kiểu nổi thực được chuyển thành kiểu unsigned. Do đó, phạm vi các giá trị nổi thực tế di động là (−1, Utype_MAX+1).

Đoạn này giống hệt nhau trong C99, chỉ chú thích cuối trang có số khác (50).

Đối với hành vi không xác định, nó không phải là không phổ biến rằng các hành vi cho các biểu thức đánh giá tại thời gian biên dịch khác với runtime-evalued, ví dụ

1 << width_of_type 

thường được đánh giá là 0 nếu khoảng cách thay đổi được đưa ra như một biểu thức liên tục và 1 nếu nó là giá trị thời gian chạy.

Lý do dẫn đến các hành vi khác nhau cho cùng mã, theo như tôi thu thập được, vì hành vi không xác định là giấy phép cho trình biên dịch tạo ra bất cứ thứ gì, nó cũng có thể làm điều đơn giản và/hoặc nhanh nhất và điều đơn giản/nhanh nhất trong quá trình biên dịch có thể khác với điều đơn giản/nhanh nhất trong thời gian chạy.

+0

Tôi có đang sử dụng chuẩn C99 không? Các câu hỏi liên quan khác đã chỉ ra hành vi đúc (giữa các kiểu tách rời) được thực hiện. Ngoài ra, tôi đang sử dụng các loại đã ký. – Ioan

+0

Không, C99 có cùng công thức. Nó chỉ dành cho các chuyển đổi giữa các kiểu tích phân mà hành vi được xác định thực hiện.(Chú thích cuối cùng nhấn mạnh rằng hành vi này cũng không xác định được đối với các kiểu mục tiêu chưa ký, trái với các chuyển đổi giữa các kiểu tách rời, ở đó hành vi được xác định hoàn toàn khi mục tiêu chưa được ký.) –

+0

Tôi nhận ra không xác định nghĩa là không có câu trả lời, nhưng tôi hy vọng hành vi có thể nhất quán hoặc có lẽ gợi ý tại một số lý do ... – Ioan

0

Như đã trả lời, "không xác định" không có nghĩa là "xác định thực hiện".

Nếu có rủi ro là giá trị của bạn sẽ vượt quá giới hạn, vì vậy bạn nên xác minh phạm vi trước khi chuyển đổi. Hoặc bạn có thể sử dụng một số thư viện, ví dụ: với các chức năng tăng cường toán học như itrunc (double) bạn sẽ nhận được tăng :: math :: rounding_error khi ra khỏi phạm vi (unfortunatelly Tôi không biết liệu bạn có thể làm cho nó hoạt động với int16_t của bạn).

http://www.boost.org/doc/libs/1_53_0/libs/math/doc/sf_and_dist/html/math_toolkit/utils/rounding/trunc.html

Đối với lập luận tại sao hành vi có thể khác nhau: Có lẽ bản thực hiện các bit đại diện cho các giá trị, nó nhận ra rằng nó được ra khỏi phạm vi và nó bỏ mà không cần quan tâm đến các bit dấu lạ mà vẫn được thiết lập để một giá trị ngẫu nhiên.