2017-07-19 62 views
5

Poniższy kod działa:Dane zamieszanie w C

int main(void) 
{ 
    float f = get_float(); 
    int i = round(f*100); 
    printf("%i\n", i); 
} 

Jednak jeśli kodowanie błędów generowane w ten sposób:

printf("%i\n", round(1.21*100)); 

Wyjście mówi round(1.21*100) jest float. Dlaczego więc nie jest w porządku?

+3

Kiedy 'wartość float' jest przypisany do' wartości int', wewnętrzna przemiana zachodzi. 'round()' daje podwójną wartość, więc jeśli nie zostanie wykonana żadna konwersja, jej wartość pozostaje podwójna. W tym określonym przypadku 'printf ("% i \ n ", runda (1,21 * 100)),' nie jest wykonywana żadna konwersja, więc wymaga specyfikacji '% f', aby wydrukować wartość float. – Sma

Odpowiedz

15

Kiedy robisz

int i = round(f*100); 

konwertowanie wynikiem double funkcji round. Przekonwertowany wynik jest przechowywany w zmiennej int zmienna i, która może być używana w formacie "%i", ponieważ oczekuje argumentu w postaci int.

Po przekazaniu wyniku double z round bezpośrednio jako argumentu do formatu, który oczekuje, że masz format niezgodny z formatem i typy argumentów. To prowadzi do nieokreślonego zachowania .

Konwersja wykonana jest w zaproszeniu do printf, i żadna konwersja może być wykonane ponieważ kod wewnątrz funkcji printf nie zna rzeczywisty typ argumentu. Wszystko, co wie, to format "%i". Wszystkie możliwe informacje o typie są tracone dla funkcji zmiennych-argumentów.

+0

cóż, "nie jest dokonywana żadna konwersja", domyślne promocje argumentów są jednak wykonywane. –

+0

@AnttiHaapala No cóż, ponieważ funkcja zwraca wartość 'double', a domyślna promocja argumentu to" double ", w tym konkretnym przypadku nie jest dokonywana żadna konwersja. –

5

Dzieje się tak ze względu na automatyczne odlewanie. W printf automatyczne sortowanie nie działa. Kiedy mówisz% i, to po prostu oczekuje liczby całkowitej, nie może przekonwertować podwójnie na liczbę całkowitą, a następnie wydrukować.

W operacji przypisania, podwójne jest konwertowane na liczbę całkowitą jako pierwszą, a następnie przypisywane jest do lewego argumentu operatora =. Mam nadzieję, że to pomoże.

4

To jest trochę powielania, ale być może pomaga dla lepszego zrozumienia:

  1. round() ma następujący prototyp:

    double round(double x); 
    

    więc zwraca double.

  2. Jest niejawna konwersja od double do int w C, więc pisanie

    int i = round(f*100); 
    

    przeliczy wynik round() do int.

  3. Jeśli masz funkcję, która oczekuje int, np.

    void printMyNumber(int number) 
    { 
        printf("%i\n", number); 
    } 
    

    można nazwać tak:

    printMyNumber(round(f*100)); 
    

    i niejawna konwersja działa zgodnie z oczekiwaniami, ponieważ kompilator widzi oba typy (typ zwrotny od round() oraz oczekiwany typu argument printMyNumber()).

  4. Powód ten nie działa z printf() jest to, że prototyp printf() wygląda następująco:

    printf(const char *format, ...); 
    

    więc, z wyjątkiem pierwszego argumentu, rodzaje argumentów są nieznaną. Dlatego wszystko, co przekazujesz, jest przekazywane bez żadnej konwersji (z wyjątkiem default argument promotions). Oczywiście, można użyć obsady osiągnięcie wyraźną przemianę zamiast:

    printf("%i\n", (int) round(f*100)); // <- this is fine