#include <stdio.h>
int main() {
float a = 1234.5f;
printf("%d\n", a);
return 0;
}
Bir 0!! Bu nasıl mümkün olabilir? Gerekçe nedir?
Ben kasten bir koyduk %diçinde printfdavranışını incelemek için deyimi printf.
Yanıtlar:
Bunun nedeni bir %dbeklemesidir, intancak siz bir şamandıra sağladınız.
Şamandırayı yazdırmak için %e/ %f/ öğesini kullanın %g.
Neden 0'ın yazdırıldığına dair: Kayan nokta numarası, doublegönderilmeden önce dönüştürülür printf. Little endian'da çift gösterimde 1234,5 sayısı
00 00 00 00 00 4A 93 40
A %d, 32 bitlik bir tamsayı kullanır, bu nedenle sıfır yazdırılır. (Bir test printf("%d, %d\n", 1234.5f);olarak çıktı alabilirsiniz 0, 1083394560.)
Neden 6.5.2.2 / 7'den prototip olan printf'e floatdönüştürüldüğüne gelince,doubleint printf(const char*, ...)
Bir işlev prototip tanımlayıcısındaki üç nokta gösterimi, argüman türü dönüşümünün bildirilen son parametreden sonra durmasına neden olur. Varsayılan bağımsız değişken yükseltmeleri, takip eden bağımsız değişkenler üzerinde gerçekleştirilir.
ve 6.5.2.2/6'dan itibaren,
Çağrılan işlevi belirten ifade, prototip içermeyen bir türe sahipse, her bağımsız değişkende tamsayı yükseltmeleri gerçekleştirilir ve türe sahip bağımsız değişkenler
floatyükseltilirdouble. Bunlara varsayılan bağımsız değişken yükseltmeleri denir .
(Bunu öğrendiği için teşekkürler Alok.)
printfdeğişken bir fonksiyondur ve standart, değişken fonksiyonlar için a'nın geçmeden önce floatdönüştürüldüğünü söyler double.
printf() çağırır .
Teknik olarak hiçbir orada konuşma , her kütüphane uygular kendi ve bu nedenle, çalışmanın çalışmakla yönteminiz sen çok kullanmak gitmiyor ne yaptığını yaparak davranış 'ın. Sisteminizin davranışını incelemeye çalışıyor olabilirsiniz ve eğer öyleyse, belgeleri okumalı ve kitaplığınız için mevcutsa kaynak koduna bakmalısınız . printfprintfprintfprintf
Örneğin, Macbook'umda çıktıyı 1606416304programınızla alıyorum .
Bir geçerken, söyledikten floatvariadic işleve, floatbir şekilde geçirilir double. Yani, programınız abir double.
Bir bayt incelemek için double, gördüğünüz bu cevabı burada SO üzerinde son soruya.
Hadi bunu yapalım:
#include <stdio.h>
int main(void)
{
double a = 1234.5f;
unsigned char *p = (unsigned char *)&a;
size_t i;
printf("size of double: %zu, int: %zu\n", sizeof(double), sizeof(int));
for (i=0; i < sizeof a; ++i)
printf("%02x ", p[i]);
putchar('\n');
return 0;
}
Yukarıdaki programı çalıştırdığımda şunu elde ederim:
size of double: 8, int: 4
00 00 00 00 00 4a 93 40
Yani, ilk dört baytı double0 çıktı, bu yüzden aramanızın 0çıktısını almış olabilirsiniz printf.
Daha ilginç sonuçlar için programı biraz değiştirebiliriz:
#include <stdio.h>
int main(void)
{
double a = 1234.5f;
int b = 42;
printf("%d %d\n", a, b);
return 0;
}
Yukarıdaki programı Macbook'umda çalıştırdığımda şunu elde ederim:
42 1606416384
Bir Linux makinesindeki aynı programla şunu elde ederim:
0 1083394560
intargümanların argümanlardan farklı kayıtlarda geçirilmesinden dolayı double. printfile 42 %dolan intargümanı alır ve %dikinci intargüman olmadığından muhtemelen ikinci önemsiz yazdırır .
%dbelirteci söylerprintf bir tamsayı beklemek. Dolayısıyla, float'ın ilk dört (veya platforma bağlı olarak iki) baytı bir tamsayı olarak yorumlanır. Sıfır olurlarsa, sıfır yazdırılır
1234.5'in ikili gösterimi şuna benzer
1.00110100101 * 2^10 (exponent is decimal ...)
floatAslında IEEE754 çift değerlerini temsil eden bir C derleyicisiyle , baytlar (hata yapmazsam)
01000000 10010011 01001010 00000000 00000000 00000000 00000000 00000000
Çok az dayanıklı (yani en önemsiz bayt önce gelen) bir Intel (x86) sisteminde, bu bayt dizisi ilk dört bayt sıfır olacak şekilde tersine çevrilir. Yani neprintf çıktı ...
IEEE754'e göre kayan nokta gösterimi için Bu Wikipedia makalesine bakın .
Bunun nedeni, ikili sayıdaki bir kayan noktaların temsilidir. Bir tam sayıya dönüştürme onu 0 olarak bırakır.
Tanımlanmamış davranışı çağırdığınız için: printf () yönteminin sözleşmesini parametre türleri hakkında yalan söyleyerek ihlal ettiniz, böylece derleyici ne isterse yapmakta özgürdür. Programın çıktısını "dksjalk is a ninnyhead !!!" yapabilir. ve teknik olarak yine de doğru olacaktır.
Nedeni, bu printf()oldukça aptalca bir işlev. Türleri hiç kontrol etmez. İlk argümanın bir olduğunu söylerseniz int(ve %dbununla birlikte söylediğiniz şey budur ), size inanır ve yalnızca bir için gereken baytları alır int. Bu durumda, makinenizin dört bayt intve sekiz bayt kullandığını varsayarsak double( içeriye floatdönüştürülür ), ilk dört baytı yalnızca sıfır olur ve bu yazdırılır.doubleprintf()a
%d ondalık
%f yüzer
bunlardan daha fazlasını burada görün .
0 alıyorsunuz çünkü kayan sayılar ve tam sayılar farklı şekilde temsil ediliyor.
Yalnızca ilgili veri türüyle (int, float, string, vb.) Uygun biçim belirticisini (% d,% f,% s, vb.) Kullanmanız gerekir.
Tam sayı değil. Kullanmayı deneyin %f.