24 Mayıs 2015 Pazar

C'de Sayı Türleri ve Otomatik Sayı Dönüşümleri

 Tamsayı türleri :
-----------------
signed char - 1 byte
unsigned char - 1 byte
signed short short>=char
unsigned short short>=char
signed int int>=short
unsigned int int>=short
signed long long>=int
unsigned long long>=int

2 Tamsayı sabiti int, unsigned int, long, unsigned long türlerinden
ilk uygun tür olacak şekilde belleğe yerleştirilir.
Literal Characters :
---------------------
2U Tamsayı sabiti unsigned int, unsigned long türlerinden
ilk uygun tür olacak şekilde belleğe yerleştirilir.

2L Tamsayı sabiti long, unsigned logn türlerinden
ilk uygun tür olacak şekilde belleğe yerleştirilir

2UL unsigned long

Gerçek sayı türleri (IEEE 754)
-------------------
float
double
long double

2.3 double
2.3F float
2.3L long double

2F float
2. double
2.0 double
*/
foo(12.3F);

printf("%d\n", d);

/*
Otomatik Sayı dönüşümleri (imlicit type convert)
-------------------------------------------
1. int'e yükseltme
---------------------
a. char , short türleri önce int türüne yükseltilir.
b. short<int ise signed int
c. sizeof(signed short) == sizeof(signed int) signed int
d. sizeof(unsigned short) == sizeof(unsigned int) unsigned int
----------------------------------------
2. long double <işlem> <!long double> = long double
3. <double> <işlem> <!double> = double
4. float <işlem> <tamsayı> = float
5. unsigned long <işlem> <!unsigned long & tamsayı> = unsigned long
6. signed long <işlem> <tamsayı & !long> = signed long
7. unsigned int <işlem> signed int = unsigned int

İstisna1 : sizeof(short) == sizeof(int)
<signed short> <işlem> <signed int> = unsigned int
İstisna2 : sizeof(int) == sizeof(long)
<signed int> <işlem> <signed long> = unsigned long
*/
char ch = -1;
if (ch > 100000U)
printf("Doğru\n");
else
printf("Yanlış\n");

int x1 = -23;
unsigned int y = 2;

printf("x1 = %u\n", x1);
printf("%lf",(float)(x1*y));

func();

extern int g;
g = 13;

return 0;
}


C'de ve C++ Bildirim Ve Tanımlama Farkı

C derleyicileri bildirimini görmediği fonksiyonların geriye int (imlicit int) döndürdüğünü kabul eder. Ve bildirim yapılmadan o fonksiyonu kullandırmaya izin verir. C dilinde bildirim esnasında parametrelerin bildirimi zorunlu değildir.

CPP'ta bildirim veya tanımlama görülmeden fonksiyon kullanılamaz. Bildirim esnasında parametrelerin bildirilmesi gerekir.


C'de Bilinirlik Alanı (Scope) , Ömür (Storage Duration) Kavramı ve Değişken Tanımlayıcıları (-Taslak-)


Bilinirlik alanı veya  kapsam veya scope veya menzil ; bir nesnenin ismi ile kullanılabildiği alandır.
1. File scope (örnek: global değişkenler)
2. function scope (örnek: goto label)
3. function declaration scope (örnek: fonksiyon bildirimleri)
4. block scope (örnek: parametre ve yerel değişkenler)

Dosya faaliyet alanı:  Bir tanımlama fonksiyonların dışında yapıldığı zaman tanımlanan değişken dosya faaliyet alanına sahiptir.  Bunlar tanımlamanın yapıldığı noktadan dosyanın sonuna kadar bütün fonksiyonlar tarafından tanınır ve kullanılırlar.  Global değişkenle, fonksiyon tanımlamaları ve fonksiyon prototipleri dosya faaliyet alanına girer.
Blok faaliyet alanı:  Bir blok içerisindeki bütün bildiriler blok faaliyet alnına sahiptir.  Bunların faaliyet alanı blok sonunu gösteren } işaretine kadardır.  Bloklar iç içe yazıldığında dıştaki blok içerisindeki değişkenler içteki blok içerisinde de geçerlidir.  Dıştaki ve içteki bloklar aynı isimde değişkenlere sahip olabilirler, ancak iç bloktaki değişken dış bloktakini maskeler.
Fonksiyon faaliyet alanı:  Fonksiyon faaliyet alanı da blok faaliyet alnı gibi düşünülebilir.  Fonksiyon parametre listesinde ve gövdesinde tanımlanan değişkenler yalnızca o fonksiyon içerirsinde geçerlidirler.  Static anahtar kelimesi ile tanımlanmış olan yerel değişkenler programın çalışmasından sonuna kadar bellekte tutulurlar ancak blok faaliyet alanına sahiptirler.  Faaliyet alanları değişkenlerin ömürlerinin etkilemez. 

Bilinirlikte dar kapsamlı değişken geniş kapsamlı değişkeni maskeleyecektir. C ‘de İsim gizlemesi diye bir kavram vardır.
Fonksiyon tanımlaması yaparken (int x,int y) benzeri parantez içi ifadelerin fonksiyonun kapanış parantezine kadar aktif olduğu bilinmesi gerekmektedir.

image

Bir alanda hem üst bir kapsama sahip hem de yerel bir değişken varsa üstü kullanmanın bir yolu yoktur. Örnek vermek gerekirse

image

C’de ömür kavramı 3’e ayrılır;
  1.   Statik
  2.   Otomatik
  3.   Dinamik
  • Statik Ömür : Hayatını programın başından sonuna kadar sürdürmektedir.
  • Otomatik Ömür : Bir kodun yürütülmesi sırasında bellekte kalan kodun çalışması sonlandığında bellekten silinen bir ömür çeşitidir.
  • Dinamik Ömür : Programın çalışıp bitmesiyle ilgili bir ömür anlayışı olmayan ne zaman istersek hayata geçen ne zaman istersek hayatı sonlanacaktır.

Atama (ingilizce overwrite ) hayatta olan bir nesneye yapılır. ilk değer verme hayata gelirken aldığı değer olacaktır.
  • Global değişkenler Static Ömürlüdür.
  • Fonksiyon içinde ve parametre olarak tanımlananlar Otomatik Ömürlüdür.
  • Static Ömürlü olan değişkenler ilk değer verilmezse 0 değeri otomatik olarak verilir.

ÖNEMLİ: Stringler yani iki tırnak içinde olan ifadeler C'de static ömürlüdür. Mesela printf(“Hello World”) ifadesi içinde “Hello World” ifadesi static ömürlüdür ve program sonlanana kadar ömrünü sürdürür.
  • Program main ile başlar ve main bittiğinde program sonlanır. main içine yazılan değişken program sonuna kadar ömrünü sürdürse de bu o değişkenin static değişken olduğu anlamına GELMEZ.
  • Static ömürlü değişkenler hayata main fonksiyonu çağrılmadan gelirler.
  • Static ömürlü bir değişkenle static ömürlü olan global değişken birbirinden farklıdır. Static ömürlü değişkenler tanımlandığı alanda kullanılır ve program sonlana kadar saklanır ve o alanda kullanılır fakat global değişkenlerde static’tir ve her yerden erişme imkanı vardır.

Çöp değer (garbage value) bellekte var olan silinmiş yani üzerine yazılabilir (eski değerlerdir). Otomatik ömürlü değişkenler çöp değerle başlar ve set edilmezse yanlış sonuçlar doğurur. Sonuç olarak otomatik ömürlü değişkenlere değer atamadan kullanmak hatalı olacaktır.

Kısaca otomatik ömürlü değişkenler garbage value ile başlar. Bu yüzden kullanmadan önce set etmek gerekir.

Geçici Nesne:
Çağrılan bir fonksiyon geri dönüş değerini geçici bir değişkene atar. Fonksiyonu çağrında bu değeri bu geçici değişkenden alarak işlem yapar. Ve orada geçici değişken sonlanmaktadır. Fakat fonksiyon çağrıldığında fonksiyon geçici değişkene bir şey göndermez ( bu C ‘de olası bir durumdur ) ise  (Programcının hatalı kod yazımından dolayı) bu durumda geçici değişken dinamik ömürlü olduğundan dolayı garbage value değeri üzerinden işlem yapılır ve hatalı sonuçlar oluşabilir.

Linkage (Bağlantı)

Birden çok kaynak kullananıldığında, bir öğe yalnızca o andaki kaynak tarafından biliniyor olabileceği gibi, onu öteki kaynaklar da biliyor olabilir.


auto Değişken Tanımlayıcısı
auto değişken tanımlayıcısı C ile B dili arasında uyum sağlamak amacı ile otomatik değişken bildiriminde kullanılır. C'de otomatik değişkenler LOKAL değişkenler olduğundan, ayrıca auto değişken tanımlayıcı kelimesini kullanmanıza gerek yoktur. Genellikle, bu tanımlayıcı ile C programlarında karşılaşma olanağınız pek yoktur.
extern Değişken Tanımlayıcısı
C dilinde yazılan uzun programlar derleme zamanını çok artıracağı için, genellikle uzun programlar iki veya daha fazla dosyaya bölünerek derlenir. Bu sistemden aynı zamanda farklı amaçlarla kullanılan kodların düzenlenmesi içinde faydalanılır. Bir proje içinde içinde yer alan bu dosyalar tek bir komutla ayrı ayrı derlendikten sonra birleştirilerek tek bir çalışan .exe uzantılı dosya oluşturulur. Bu durumda, bir dosya içinde tanımladığınız global değişkenler diğer dosya içinde tanınmazlar. Eğer bir dosya içinde tanımladığınız global değişkenlerin diğer dosyalar içinde geçerli olmasını isterseniz, diğer dosyalarda yer alan bütün fonksiyonların dışında yaptığınız değişken tanımlamalarının baş tarafına extern ifadesini getirmeniz gerekir. extern ifadesinin kullanılmasını örnekler üzerinde incelemeye çalışalım:
Aşağıda verilen iki dosyayı deneme1.c ve deneme2.c adları ile bir proje içine kaydettikten sonra derleyicinizi kullanarak projeyi derler ve deneme.exe adlı tek bir program adı ile çalıştırırsanız aşağıdaki satırları ekrana yazar:
10 15
10 7
Programda, ilk satırı ekrana yazan deneme2.c, ikinci satırı ekrana yazan ise deneme1.c dosyasındaki işlem satırlarıdır. 1 sayısı ile gösterilen satırda yer alan işlem satırı fonksiyon bildirimi için kullanılmakta olup ilerideki bölümlerde ele alınacaktır.
/* deneme1.c */
int gid1 = 10;

void fonk1(void); /* 1 */ 

main()
{
  int id2;

  id2 = 7;
  fonk1();
  printf("%d %d", gid1, id2);
}

/* deneme2.c */
extern int gid1;

void fonk1 (void)
{
  int id2;

  id2 = 15;
  printf("%d %d", gid1, id2);
  printf("\n");
}
Kısaca özetlersek, extern değişken tanımlayıcısı, uzun bir program birden fazla dosyaya bölündüğünde, ilk programda kullanılan global bir değişkeni diğer dosyalara tanıtmak için kullanılır.
register Değişken Tanımlayıcısı
Eğer programınızda bir değişkeni çok sık kullanıyorsanız, bu değişken bildiriminin başında register ifadesini kullanmanız programınızın hızını artırır. çünkü, bilgisayar bu şekilde tanımlanan değişkenlere daha hızlı bir şekilde ulaşır. Bunun nedeni, register değişkenlerin Merkezi İşlem Biriminin (CPU) yazmacında saklanmış olmasıdır.
Ancak, CPU'da sınırlı sayıda yazmaç bulunduğu için, eğer register değişken sayısı çok fazla olursa, bilgisayar belli bir sayıdan sonraki register değişkenleri normal değişken olarak kabul eder. Bu tanımlamayı yaptığımızda derleyiciye bu değişkene öncelik tanıyarak, performansı artırması için bellek yerine CPU içinde yer alan yazmaçlara yerleştirmesi konusunda bir istek yapılmış olur. Ama, bu isteğin mutlaka yerine getirileceğine dair bir garanti yoktur. Bu nedenle, çok sık kullanılan değişkenleri register olarak tanımlamak gerekir. Buna örnek olarak, döngüleri kontrol etmekte kullanılan değişkenler gösterilebilir. Bu değişkenler çok sık kullanıldığından programınızın performansı hissedilir ölçüde artacaktır.
Sadece lokal değişkenler ile fonksiyon parametresi olarak bildirimi yapılan değişkenlerin başında register ifadesini kullanabilirsiniz.
Bir register değişken CPU yazmacına yüklendiğinden bellek adresi olmaz. Yani, register bir değişkenin adresini tanımlamak için & işlemcisini kullanamazsınız.
static Değişken Tanımlayıcısı
static değişken tanımlayıcısını lokal ve global değişkenlerle birlikte kullanabilirsiniz. Normal olarak, içinde lokal değişken tanımlanan bir fonksiyonu her çağırmanızda, lokal değişken değeri yenilenir. Ancak, bir fonksiyon içinde static lokal bir değişken tanımladığınızda, fonksiyonu her çağırmanızda lokal değişken bir önceki fonksiyon çağrısındaki en son değerini korur. Sonuç olarak, static lokal bir değişkene sadece fonksiyonun ilk çağrılışında bir defaya mahsus olmak üzere değer verebilirsiniz. static lokal bir değişken kullanılmasını bir örnek üzerinde incelemeye çalışalım:
#include <stdio.h>

void fonk1 (void);
void fonk2 (void);

main()
{
  fonk1();
  fonk2();

  printf("\n");

  fonk1();
  fonk2();
  
  printf("\n");

  fonk1();
  fonk2();
}

void fonk1 (void)
{
  int id1 = 1;

  printf("%d ", id1);
  id1 = id1 + 5;
  printf("%d ", id1);
}

void fonk2 (void)
{
  static int id1 = 0;

  printf("%d ", id1);
  id1 = id1 + 9;
  printf("%d ", id1);
}
Yukarıdaki örnekte, program aşağıdaki satırları ekrana yazar:
1 6 0 9
1 6 9 18
1 6 18 27
Program fonk1() ve fonk2() fonksiyonlarını sırasıyla üçer kez çağırarak lokal olarak tanımlanmış değişken değerlerini ekrana yazdırır. Her iki fonksiyonda da lokal değişken değerleri artırılmasına rağmen sadece fonk2() fonksiyonu içindeki id1 değişkeni bir önceki fonksiyon çağrısında aldığı değeri korumaktadır. Bu olanağı sağlayan değişkenin statik tanımlanmış olmasıdır.
static değişken tanımlayıcısını global değişkenlerle kullanabilirsiniz. static global bir değişken tanımladığınızda, bu değişkeni sadece içinde tanımlandığı dosyada bulunan fonksiyonlar kullanabilir. Bunun yanında, aynı programa ait farklı dosyalarda bulunan ve aynı isme sahip biri normal diğeri de static olan iki global değişken tanımlayabilirsiniz. Bu özelliği bir örnek üzerinde incelemeye çalışalım:
Aşağıda verilen iki dosyayı deneme1.c ve deneme2.c adları ile bir proje içine kaydettikten sonra derleyicinizi kullanarak projeyi derler ve deneme.exe adlı tek bir program adı ile çalıştırırsanız aşağıdaki satırları ekrana yazar:
18 24
/* deneme1.c */
#include <stdio.h>

void fonk1 (void);
void fonk2 (void);

static int gid1 = 18;

main()
{
  fonk1();
  fonk2();
}

void fonk1 (void)
{
  printf("%d ", gid1);
}

/* deneme2.c */
#include <stdio.h>

int gid1 = 24;

void fonk2 (void)
{
  printf("%d", gid1);
}
Program, her iki dosyada gid1 adlı birer adet global değişken tanımlar. Aynı isme sahip 2 değişken olduğu halde deneme1.c dosyasındaki değişkenin static olarak tanımlanması farklı 2 değişken olarak algılanmalarını sağlar.
const ve volatile Değişken Tanımlayıcıları
C'de, değişken bildirimlerinin başında kullanılan const ve volatile tanımlayıcıları ile değişkenlere farklı özellikler kazandırabilirsiniz. Eğer değişken bildiriminin başına const ifadesini getirirseniz, program değişkenin değerini hiç bir şekilde değiştiremez. const değişkenlere bir ilk değer verilebilir.
Şimdi, const tanımlayıcısının kullanılmasını bir örnekle incelemeye çalışalım:
/* Bu program derleyici tarafından derlenmez. */

#include <stdio.h>

main()
{
  const int id1 = 1;

  id1 = 7;
  printf("%d ", id1);
}
Yukarıdaki programı derlemeye çalıştığınızda hata verir. Çünkü, const olarak tanımlanmış bir değişken değeri değiştirilemez.
Eğer bir değişken bildiriminin başına volatile ifadesini getirirseniz, bu değişken değerini program içinde herhangi bir şekilde değiştirmeniz mümkündür. volatile ifadesi const ifadesinin yaptığı işlemin tersini yapar.



C Dilinde Operatör Öncelikleri

SEVİYE

OPERATÖR

TANIM

ÖNCELİK YÖNÜ





1
( )
öncelik kazandırma ve fonksiyon çağırma
soldan sağa

[ ]
index operatörü (subscript)


.
yapı elemanına ulaşım (structure access)


->
yapı elemanına gösterici ile ulaşım

2
+
işaret operatörü (unary)
sağdan sola

-
işaret operatörü (unary)


++
1 artırma (increment)


--
1 eksiltme (decrement)


~
bitsel değil (bitwise not)


!
mantıksal değil (logical not)


*
içerik operatörü (indirection)


&
adres operatörü (address of)


sizeof
sizeof operatörü


(tür)
tür dönüştürme (type cast operator)

3
*
çarpma (multiplication)
soldan sağa

/
bölme (division)


%
modulus (bölümden kalan)

4
+
toplama (addition)
soldan sağa

-
çıkarma (suntraction)

5
<<
bitsel sola kaydırma (bitwise shift left)
soldan sağa

>>
bitsel saga kaydırma (bitwise shift right)

6
<
küçüktür (less than)
soldan sağa

>
büyüktür (greater than)


<=
küçük eşittir (less than or equal)


>=
büyük eşittir (greater than or equal)

7
==
eşittir (equal)
soldan sağa

!=
eşit değildir (not equal to)

8
&
bitsel VE (bitwise AND)
soldan sağa
9
^
bitsel EXOR (bitwise EXOR)
soldan sağa
10
|
bitsel VEYA (bitwise OR)
soldan sağa
11
&&
mantıksal VE (logical AND)
soldan sağa
12
||
mantıksal VEYA (logical OR)
soldan sağa
13
?:
koşul operatörü (conditional operator)
sağdan sola
14
=
atama (assignement)
sağdan sola

+=
işlemli atama (assignment addition)


-=
işlemli atama (assignment subtraction)


*=
işlemli atama (assignment multiplication)


/=
işlemli atama (assignment division)


%=
işlemli atama (assignment modulus)


<<=
işlemli atama (assignment shift left)


>>=
işlemli atama (assignment shift right)


&=
işlemli atama (assignment bitwise AND)


|=
işlemli atama (assignment bitwise OR)


^=
işlemli atama (assignment bitwise EXOR)

15
,
virgül operatörü (comma)