2013-02-08 18 views
10

hãy có một cái nhìn tại mã này:Mặc nhiên đúc một phao liên tục

#include <stdio.h> 

int main(void) 
{ 
    short s; 
    int i = 65696; 
    float f = 65696.0F; 

    printf("sizeof(short) = %lu\n", sizeof(short)); 

    s = i; 
    printf("s = %hd\n", s); 
    s = f; 
    printf("s = %hd\n", s); 

    s = 65696; 
    printf("s = %hd\n", s); 
    s = 65696.0F; 
    printf("s = %hd\n", s); 

    return 0; 
} 

Nó đã cho đầu ra như:

sizeof(short) = 2 
s = 160 
s = 160 
s = 160 
s = 32767 

Trong dòng cuối cùng tại sao nó là 32767 và không 160? Sự khác biệt giữa việc nói f = 65696.0F; s = f;s = 65696.0F; là gì?

Trả lời

13

Bởi vì nếu phần không thể tách rời của giá trị nổi không thể thể hiện trong loại mới, thì chuyển đổi là hành vi không xác định.

Trong trường hợp của bạn, SHRT_MAX có thể là 32767 và do đó phần tách rời của 65696.0F sau đó không thể đại diện trong đối tượng short.

+7

+1. Cụ thể, 6.3.1.4/1: * "Khi một giá trị hữu hạn của kiểu thả nổi thực được chuyển đổi thành một kiểu số nguyên khác với _Bool, phần phân số bị loại bỏ (nghĩa là giá trị được cắt ngắn về 0). một phần không thể được biểu diễn bằng kiểu số nguyên, hành vi không xác định) "* – Jon

+0

@Jon Vậy tại sao không cùng một điều xảy ra khi tôi nói' f = 65696.0F; s = f'? – rootkea

+3

@rootkea đây là hành vi không xác định là tốt và vâng hành vi không xác định có thể không đoán trước được. – ouah

1

Đây là "hành vi không xác định", có nghĩa là trình biên dịch được tự do thực hiện những gì nó muốn. Nhưng "không xác định" không có nghĩa là "không giải thích được".

gì trình biên dịch được thực hiện trong trường hợp s = f được chuyển đổi f đầu tiên với giá trị int 65.696, và sau đó gán 65.696 đến s, mà tràn và lá 160. Trình biên dịch thực hiện điều này vì có một lệnh CPU để chuyển đổi một số dấu chấm động thành số nguyên 32 bit, nhưng không trực tiếp vào số nguyên 16 bit

Trình biên dịch đang làm với s = 65696.0F đơn giản hơn: Biết rằng 65696.0 nằm ngoài phạm vi, vì vậy nó gán giá trị cao nhất có sẵn cho s, xảy ra là 2^15-1 = 32767.

Bạn có thể xác minh điều này nếu bạn đọc mã lắp ráp các trình biên dịch tạo ra cho s = f (ví dụ sử dụng -S switch với gcc):

movss -4(%rbp), %xmm0  # Load float from memory into register xmm0 
    cvttss2si  %xmm0, %eax # Convert float in xmm0 into signed 32 bit, store in eax 
    movw %ax, -10(%rbp)   # Store lower 16 bits of eax into memory 
    movswl -10(%rbp), %eax  # Load those 16 bits into eax, with sign extend 

Các hướng dẫn cuối cùng clobbers 16 bit cao của% eax, thiết lập nó cho tất cả 0s trong trường hợp này .

gì nó tạo ra cho s = 65696.0F là đơn giản:

movw $32767, -10(%rbp)  # Store the lower 16 bits of 32767 into memory 
    movswl -10(%rbp), %eax  # Load those 16 bits into eax, with sign extend 
Các vấn đề liên quan