[Çözüldü] Daha Önceden Yazılmış Bir Fonksiyonu Tekrardan Yazmak

Başlatan blacksnow, 07 Nisan 2015 - 10:30:08

« önceki - sonraki »

0 Üyeler ve 6 Ziyaretçi konuyu incelemekte.

blacksnow

Fonksiyonların nasıl çalıştığını anlamak için birkaç deneme yapıyordum ve şöyle bir sorunla karşılaştım;
Aşağıdaki kodda -5.0 için benim yazdığım fonksiyonun sonucu dönüyor.-5 değeri için ise kendi kütüphanesindeki fonksiyonun sonucu döndürülüyor.
abs fonksiyonuna parametre olarak double bir değer girdiğimde, neden benim fonksiyonuma gidiyor da diğerine gitmiyor?.Bu karar neye göre veriliyor?
#include<stdio.h>
main()
{
    printf("%d", abs(-5.0));
    printf("%d\n", abs(-5));
}
int abs(int n) {
    return 1;
}

Sonuç
1
5

Ayrıca başlık dosyalarına "stdlib.h" eklenirse ikiside benim yazdığım fonksiyona girmiyor.Bunun da nasıl olduğunu açıklayabilir misiniz?
Şimdiden teşekkürler.

thoron

Alıntı yapılan: blacksnow - 07 Nisan 2015 - 10:30:08
Fonksiyonların nasıl çalıştığını anlamak için birkaç deneme yapıyordum ve şöyle bir sorunla karşılaştım;
Aşağıdaki kodda -5.0 için benim yazdığım fonksiyonun sonucu dönüyor.-5 değeri için ise kendi kütüphanesindeki fonksiyonun sonucu döndürülüyor.
abs fonksiyonuna parametre olarak double bir değer girdiğimde, neden benim fonksiyonuma gidiyor da diğerine gitmiyor?.Bu karar neye göre veriliyor?
#include<stdio.h>
main()
{
    printf("%d", abs(-5.0));
    printf("%d\n", abs(-5));
}
int abs(int n) {
    return 1;
}

Sonuç
1
5

Ayrıca başlık dosyalarına "stdlib.h" eklenirse ikiside benim yazdığım fonksiyona girmiyor.Bunun da nasıl olduğunu açıklayabilir misiniz?
Şimdiden teşekkürler.

abs fonksiyonu stdlib.h ve math.h'ta var bildiğim kadarıyla. bir de kodunla çıktın uymuyor. kodun tamamını atsana. bir de fonksiyonunun prototipini tanımladın mı?

Reverser


#include <stdio.h>

int abs(double  n);

main()
{
    printf("%d\n", abs(-5.0));
    printf("%d\n", abs(-5));
}
int abs(double n) {
    return 1;
}


fonksiyon prototipi kullanmayı deneyin birde. -5.0 için sizin yazdığınız fonksiyonun sonucunun dönmesi normal sanıyorum çünkü, kütüphanede tanımlanan abs(); fonksiyonu sadece integer parametre alıyor.

XFCE ROCKS !
Powered by Thunar & XFWM4



thoron

fonksiyonun prototipini yazdım mainden önce, çalıştırdım bu sefer ikisi de 5 yazdı. fonksiyonun adını değiştirdim ikisi de 1 yazdı bu sefer olması gerektiği gibi. abs'nin stdio.h'ta olmaması gerek, derleyici mi düzeltiyor anlamadım. zaten prototip tanımlamadan mainin altındaki bir fonksiyonu mainde çağırınca gccnin first declaration bilmem ne diye hata vermesi gerek.


Mesaj tekrarı yüzünden mesajınız birleştirildi. Bu mesajın gönderim tarihi : 07 Nisan 2015 - 11:55:07

Alıntı yapılan: Reverser - 07 Nisan 2015 - 11:47:36

#include <stdio.h>

int abs(double  n);

main()
{
    printf("%d\n", abs(-5.0));
    printf("%d\n", abs(-5));
}
int abs(double n) {
    return 1;
}


fonksiyon prototipi kullanmayı deneyin birde. -5.0 için sizin yazdığınız fonksiyonun sonucunun dönmesi normal sanıyorum çünkü, kütüphanede tanımlanan abs(); fonksiyonu sadece integer parametre alıyor.



b.c:3:5: warning: conflicting types for built-in function 'abs'
int abs(double  n);


stdio.h'da varmış abs. yeni bir şey öğrendik  :)

Amenofis

Hayır stdio da yok. stdlib.h de var, birde derleyiciye tümleşik (built-in) versiyonu varmış göründüğü kadarıyla.

blackwidow

abs stdlib.h da bulunuyor ancak integer alıyor

double yollamamaya çalış dostum

ayrıca stdlib.h ı eklemediysen kendin yazabilirsin bu sefer double için çalışanını da yapabilirsin.

stdlib.h kullandıysan zaten yazdığın fonksiyon sistem kütüphanesindeki fonksiyonla çakışıcak ismini değiştirirsin

thoron

Alıntı yapılan: blackwidow - 07 Nisan 2015 - 18:26:29
abs stdlib.h da bulunuyor ancak integer alıyor

double yollamamaya çalış dostum

ayrıca stdlib.h ı eklemediysen kendin yazabilirsin bu sefer double için çalışanını da yapabilirsin.

stdlib.h kullandıysan zaten yazdığın fonksiyon sistem kütüphanesindeki fonksiyonla çakışıcak ismini değiştirirsin

double yollarsa integer'a çevirir zaten kendisi. double için çalışan fabs var math.h'ta

91011

Merhaba,

Sorun şu C dili satır satır derlenir. include ettiğin kütüphanenin içinde o fonksiyon varsa derleyici o fonksiyonun ne tür değer aldığını bilir. Böylece çalışırken ona göre hareket eder. Sen -5.0 vediğinde double tipinin standart abs fonksiyonunun kullandığı bir değer tipi olmadığını derleyici önceden biliyor bu yüzden yukarıda prototipini tanımlamadığın senin yazımş olduğun abs fonksiyonuna kontrolsüz bir şekilde değer dönüştürme işlemi yapıyor yani değeri resmen bodoslama daldırıyorsun bu pek de tercih edilen bir alışkanlık değildir değildir eğer programlama yapıyorsan * her şey bilinçli olarak senin kontrolünde olmalı en azından bize böyle öğretildi.

-5 veridiğinde ise C kodu sıra sıra çalıştığı için standart kendi kütüphanesinde olan fonksiyonun hangi değer tipi kullandığını biliyor satır satır derlendiği için seinni fonksiyon altta olduğu için senin fonksiyon işlev kazanamıyor ve böylece stanart kütüphane fonksiyonu çalışıyor.
Tanrı konuşmaz, şeytan fısıldar...

Amenofis

Bazı denemeler yaptım bu konuyla ilgili. Maalesef olay burada anlatılanlardan daha karışık. Fonksiyonun prototipinin olup olmaması, altta ya da üstte olmasının hiçbir önemi yok. C' de parametre türleri farklı olsa dahi aynı isimli fonksiyon olamaz. Fonksiyonu komple en tepeye yazsanız dahi fonksiyon içeriği bağlayıcı (linker) tarafından programa gömülüyor. Derleyici sadece imzasına bakıyor, ister sadece prototip olsun, ister tamamı olsun durum değişmiyor.

Eğer kütüphanede olan bir fonksiyon ile aynı imzada bir başka fonksiyon yazarsanız derleyici imzasına bakarak obje koduna (.o dosyası) uygun bir fonksiyon çağrısı yazıyor, her zamanki gibi. Fakat hangi fonksiyonun çağrılacağını bağlayıcı belirliyor. Bu aşamada hem sizin yazdığınız hem de kütüphanedeki olmak üzere aynı imzaya sahip iki farklı fonksiyon var. Bağlayıcı uygun fonksiyon imzasını arıyor ve bulduğunda içeriğini nihai programa yazıyor. Buradan tahmin yürüterek bağlayıcının aramaya dış kütüphanelerden başladığını söyleyebiliriz. Eğer bizim obje kodumuzdan başlasaydı kendi yazdığımız fonksiyon eşlenecekti. Bu durumun standardı yok, yani başka bir derleyicide farklı davranış olabilir.

Şimdide çözümlere geçelim. Eğer her tür için farklı fonksiyon yazmak istemiyorsanız, karışıklığı azaltmak istiyorsanız C11 ile gelen Generic macroları kullanabilirsiniz. Örnekte parametre türü int ise abs, float ise fabsf, double ise fabs otomatik olarak çağrılıyor. Herhangi bir tür dönüşümü söz konusu değil. <tgmath.h> başlığında hazır generic macrolar var, fabs dahil.

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define fabs(X) _Generic((X), \
    int: abs(X), \
    float: fabsf(X), \
    double: fabs(X))

int main()
{
    int a = fabs(-5);
    float b = fabs(-5.0f);
    double c = fabs(-5.0);
    ...
    return 0;
}

91011

 aynı isimli fonksiyon olamaz ise hata vermesi gerekmez mi ?
Tanrı konuşmaz, şeytan fısıldar...

Amenofis

#10
Derleyici bilmiyorki aynı isimli başka fonksiyon olduğunu. Başlık dosyasında sadece prototip var, aynı prototipten çok sayıda olması hata değil. Fakat içerikleriyle beraber aynı .c dosyasına yazarsan bunu göreceği için izin vermez.

#include <stdlib.h>
int abs(float);

Buna da izin vermez çünkü aynı isimli iki farklı prototip var. Çakışma olacağını bilir.

Ekleme: Çakışma demiştim ama pek doğru olmadı. Derleyici açısından bu sorunu çözmek çok basit. Hata vermesinin sebebi C standardında bunun yasak olması.

blacksnow

#11
Alıntı Yapabs fonksiyonu stdlib.h ve math.h'ta var bildiğim kadarıyla. bir de kodunla çıktın uymuyor. kodun tamamını atsana. bir de fonksiyonunun prototipini tanımladın mı?

Çıktıda bir hata yok bende aynen yazdığım gibi çıkıyor sonuç.Kodun tamamı da bu.

Alıntı YapSen -5.0 vediğinde double tipinin standart abs fonksiyonunun kullandığı bir değer tipi olmadığını derleyici önceden biliyor bu yüzden yukarıda prototipini tanımlamadığın senin yazımş olduğun abs fonksiyonuna kontrolsüz bir şekilde değer dönüştürme işlemi yapıyor yani değeri resmen bodoslama daldırıyorsun bu pek de tercih edilen bir alışkanlık değildir değildir eğer programlama yapıyorsan * her şey bilinçli olarak senin kontrolünde olmalı en azından bize böyle öğretildi.

Hocam öncelikle teşekkürler.Burada söylediklerinize göre prototipini tanımlamadığım için benim fonksiyonuma gidiyor.Ben int abs(int); olarak yukarıda prototipini tanımladığımda sonuçlar 5,5 olarak çıkıyor.Yani bu sefer iki fonksiyonda kütüphanedeki fonksiyona gidiyor.Ben burada double parametre bekleyen bir fonksiyon olmadığı için hata vereceğini düşünmüştüm.Neden hata vermeyip kendi fonksiyonuna gitti?
#include<stdio.h>
int abs(int);
main()
{
printf("%d\n", abs(-5.0));
printf("%d\n", abs(-5));
}

int abs(int n) {
return 7;
}

Sonuç
5
5


Ayrıca hiçbir fonksiyon tanımlaması yapmadan yani aşağıdaki gibi yaparsam sonuç 1,5 çıkmakta.Yani abs fonksiyonu int dışında bir değer aldığında default olarak 1 döndürüyor.Tabi bu bir tahmin bir bilgim yok fonksiyon ile.
#include<stdio.h>
main()
{
printf("%d\n", abs(-5.0));
printf("%d\n", abs(-5));
}

Sonuç
1  // burada 5 yazmıştım yanlışlıkla düzelttim.
5


Sonuç olarak farklı durumlarda farklı sonuçlar alıyorum ve kafam karıştı.


Mesaj tekrarı yüzünden mesajınız birleştirildi. Bu mesajın gönderim tarihi : 08 Nisan 2015 - 00:51:07

C' de aynı isimli fonksiyonlar tanımlanamaz.Eğer tanımlanırsa derleyici bunu farkedemez ve çalışma anında hangi fonksiyonun kullanılacağı derleyiciden derleyiciye değişir.Anladığıma göre durum bu.
Alıntı YapBaşlık dosyasında sadece prototip var, aynı prototipten çok sayıda olması hata değil.
Burayı tam olarak anlayamadım.Aynı prototip derken nasıl oluyor?Örnek verebilme şansınız var mı acaba?

91011




@blacksnow, @Amenofis in dediği gibi hata vermesi gerekirdi. Benim düşüncem okuma sırasına göreydi, 2 aynı isimli fonksiyon olduğun için derleyicinin seçim yaptığı yönündeydi. Son yazdığında görülüyorki böyle değil bu konu hakknıda konuşamayacağım derleyiciler hakında uzman değilim. Daha fazla araştırmama gerek.


Alıntı yapılan: Amenofis - 08 Nisan 2015 - 00:08:14
Derleyici bilmiyorki aynı isimli başka fonksiyon olduğunu. Başlık dosyasında sadece prototip var, aynı prototipten çok sayıda olması hata değil. Fakat içerikleriyle beraber aynı .c dosyasına yazarsan bunu göreceği için izin vermez.

#include <stdlib.h>
int abs(float);

Buna da izin vermez çünkü aynı isimli iki farklı prototip var. Çakışma olacağını bilir.

Ekleme: Çakışma demiştim ama pek doğru olmadı. Derleyici açısından bu sorunu çözmek çok basit. Hata vermesinin sebebi C standardında bunun yasak olması.
Buna izin vermiyorsa @blacksnow un üsteki iletide çalıştığına dair çıktı veriyor ben mi yanlış anlıyorum ? Normalde olmaması gerekiyor ama derlenmiş sonuçta kafa karıştırıyor.




Tanrı konuşmaz, şeytan fısıldar...

blackwidow

fabs ' ı kullanmadım hiç , o yüzden bilmiyorum

ama kendisi double girdiğinde double abs return eden bir fonksiyon yazabilir

blacksnow

#14
@91011, aşağıdaki örneği incelersek,
#include<stdio.h>
int abs(int);
int abs(float);
main()
{
printf("%d\n", abs(-11.0));
printf("%d\n", abs(-7));
}

int abs(int n) {
return 4;
}

int abs(float n) {
return 9;
}

Sonuç
c.c:4:5: error: conflicting types for 'abs'
int abs(float);
     ^
c.c:3:5: note: previous definition of 'abs' was here
int abs(int);
     ^
c.c:4:5: error: declaration for parameter 'abs' but no such parameter
int abs(float);
     ^
c.c:3:5: error: declaration for parameter 'abs' but no such parameter
int abs(int);
     ^
c.c: At top level:
c.c:14:5: error: conflicting types for 'abs'
int abs(float n) {
     ^

Burada her şey açık gibi bir prototip tanımlayıp üstüne aynı isimde farklı bir parametre ile bir yeni bir prototip yazdığımızda hata alıyoruz.

Eğer üstteki prototip tanımlamalarını silersek şu hatayı alıyoruz.Burada aslında üsteki hatadaki gibi önceki tanımlamanın nerde olduğunu note ile göstermesi gerekli fakat fonksiyon ve prototipi bizim .c dosyamızda olmadığı için gösterilemiyor.
c.c:12:5: error: conflicting types for 'abs'
int abs(float n) {
     ^


Not:Ben bir çözüm yolu aramıyorum.Eğer ararsam fonksiyonları farklı isimlerde farklı parametrelerle yazar işin içinden çıkarım.Aslında ben burada derleyici ne yapıyor onu merak ediyorum.

Amenofis

Alıntı yapılan: 91011 - 08 Nisan 2015 - 01:07:18

Buna izin vermiyorsa @blacksnow un üsteki iletide çalıştığına dair çıktı veriyor ben mi yanlış anlıyorum ? Normalde olmaması gerekiyor ama derlenmiş sonuçta kafa karıştırıyor.

#include <stdlib.h>
int abs(int);
int abs(int);
int abs(int);
...
int x = abs(-5);

Bu hata değil. Aynı prototipten çok sayıda olmasının bir önemi yok derleyici görmezden gelir. Zaten <stdlib.h> başlığında da aynı prototip var (fonksiyonun kendisi yok). Fakat;

int abs(int); // ya da #include <stdlib.h>
int abs(float);
...
int x = abs(-5);

Buna izin vermez çünkü farklı parametre türü demek farklı fonksiyon demektir, C' de yasak.

Şu an açıklığa kavuşmayan tek durum prototip olmadığı zaman abs(-5.0) ın 1 döndürmesi. Ben de denedim, değişkenin türü int değilse sürekli 1 döndürüyor. Normalde int dönüşümü yapması gerekirdi. Sanırım bu bi çeşit bug, farkedilmesi zor olduğu için de çok tehlikeli. En iyisi derleyiciye C standardının dışına çıkmamasını söylemek. Böylece bu hataya sebep olan implicit declaration durumuna izin verilmeyecek.

Bunun için şu şekilde derleyebilirsiniz: gcc -std=c11 -Wall -pedantic-errors ...

kaansef

Fonksiyon aşırı yüklenmiş. O yüzden farklı çıktılar alıyorsunuz. Siz double değer alan abs isimli bir fonksiyon tanımlamışsınız. Gerçekte o fonksiyon int değer kabul ediyor. Siz abs fonksiyonuna int değer gönderirseniz stdlib.h kütüphanesindeki fonksiyon çalışacak. Eğer double değer gönderirseniz sizin tanımladığınız fonksiyon çalışacak. (Aşırı yükleme: Aynı fonksiyonu farklı parametreler alacak şekilde yazmak. Bu sayede gönderdiğiniz parametreye göre tanımladığınız fonksiyonlardan biri çalışır.)
# 28065

Amenofis

Alıntı yapılan: kaansef - 08 Nisan 2015 - 18:06:22
Fonksiyon aşırı yüklenmiş. O yüzden farklı çıktılar alıyorsunuz. Siz double değer alan abs isimli bir fonksiyon tanımlamışsınız. Gerçekte o fonksiyon int değer kabul ediyor. Siz abs fonksiyonuna int değer gönderirseniz stdlib.h kütüphanesindeki fonksiyon çalışacak. Eğer double değer gönderirseniz sizin tanımladığınız fonksiyon çalışacak. (Aşırı yükleme: Aynı fonksiyonu farklı parametreler alacak şekilde yazmak. Bu sayede gönderdiğiniz parametreye göre tanımladığınız fonksiyonlardan biri çalışır.)

C' de fonksiyon aşırı yükleme yok, yukarıda izah ettim.

blacksnow

Alıntı YapŞu an açıklığa kavuşmayan tek durum prototip olmadığı zaman abs(-5.0) ın 1 döndürmesi. Ben de denedim, değişkenin türü int değilse sürekli 1 döndürüyor. Normalde int dönüşümü yapması gerekirdi.
@amenofis, sanırım derleyici prototipe bakarak eğer fonksiyon int değer alacak ise int dönüşümü yapıyor(denedim ve oldu).Fakat prototip tanımlamazsak neye dönüştüreceğini bilemiyor derleyici ve 1' e dönüştürüyor.Neden 1 onu ben de anlayamadım.

Alıntı YapBuradan tahmin yürüterek bağlayıcının aramaya dış kütüphanelerden başladığını söyleyebiliriz. Eğer bizim obje kodumuzdan başlasaydı kendi yazdığımız fonksiyon eşlenecekti. Bu durumun standardı yok, yani başka bir derleyicide farklı davranış olabilir.

Şimdi asıl sorun burda hala.Hocam burada söylediklerinize göre bağlayıcı fonksiyonun imzasını arıyor ve ilk bulduğunu programa yazıyor.Eğer öyleyse aşağıdaki kodda nasıl derleyiciye gömülü abs fonksiyonu ile benim fonksiyonum ayrı ayrı çalışıyor.Sadece birini seçip programa eklememiş miydi?
#include<stdio.h>
main()
{
printf("%d\n", abs(-5.0));
printf("%d\n", abs(-5));
}
int abs(int n) {
return 2;
}

Sonuç
2
5

Amenofis

Alıntı yapılan: blacksnow - 09 Nisan 2015 - 00:46:34
@amenofis, sanırım derleyici prototipe bakarak eğer fonksiyon int değer alacak ise int dönüşümü yapıyor(denedim ve oldu).Fakat prototip tanımlamazsak neye dönüştüreceğini bilemiyor derleyici ve 1' e dönüştürüyor.Neden 1 onu ben de anlayamadım.
Hayır double her zaman int e dönüşür (küsürat atılır). Sen uygun bir prototip eklediğin zaman kütüphanedeki abs çağrılıyor, sorun kalmıyor yani.

Alıntı YapŞimdi asıl sorun burda hala.Hocam burada söylediklerinize göre bağlayıcı fonksiyonun imzasını arıyor ve ilk bulduğunu programa yazıyor.Eğer öyleyse aşağıdaki kodda nasıl derleyiciye gömülü abs fonksiyonu ile benim fonksiyonum ayrı ayrı çalışıyor.Sadece birini seçip programa eklememiş miydi?
#include<stdio.h>
main()
{
printf("%d\n", abs(-5.0));
printf("%d\n", abs(-5));
}
int abs(int n) {
return 2;
}

Sonuç
2
5

Yukarıda prototip yoksa double alan abs fonksiyonun davranışı hala muamma, yani ben çözemedim. Orada neye dayanarak 2 döndüren abs yi çağırıyor bilmiyorum. int alan abs de sorun yok, tümleşik abs int alıyorsa doğru çalışıyor.
Eğer 2 döndüren fonksiyonu yukarı alırsan kütüphanedeki abs ile aynı imzaya sahip olduğundan sadece prototip işlevi görecek ve standart abs çağrılacak. Yani iki durumda da 5 dönecek.

Daha önce söylediğim gibi "implicit declaration" ı kesinlikle yasaklamanızı öneriyorum. Yani bu olay benim açımdan da öğretici oldu, ben bundan sonra sadece standart (ansi) modda derleme yapacağım.

blacksnow

@Amenofis, sanırım daha fazla şey söyleyebilmek için derleyicilerin nasıl çalıştığını iyi bilmek gerekli.Dediğiniz gibi zaten yaptığım şey C' de yasak olan bir durum yani aynı fonksiyonu iki kez yazmak.Hala kafamda tam oturmayan noktalar olsa da konuyu kapatıp daha fazla kurcalamamayı düşünüyorum.Cevaplarınız için teşekkürler.

blackwidow

Eskiden derleyeciler basitti şimdi ise complex işlemler için bazı durumlarda kendi kararlarını verebiliyorlar.


Amenofis

Birçok kullanıcı warningleri önemsemiyor. stdlib.h başlığını eklemezsek aşağıdaki çok basit durum hatalı veri üretiyor, bunu rapor etmek lazım aslında. 34 yıldır geliştirilen bir derleyicide böyle basit hatalar görmek can sıkıcı.

    double x;
    ...
    int var = abs(x);

x' ten bağımsız olarak sonuç bazen 1 bazen 2, belirsiz.