Monday, January 15, 2007

Sabitler de artık değişmeye başladı...

yarın finale gireceğim için bu gece karışık bişeyler yazmamaya karar verdim, ve kısaca size C de programlamanın ne kadar çok programcıya bırakıldığını göstermeye kadar verdim. Güzel bir trick yaparak const tanımlanan değişkenleri değiştirelim ne derseniz....

Derleyici const olarak tanımlanmış bir değişkene direk olarak bir atama yaptığınız da şöyle bir hata verecektir:

#include<iostream>
using namespace std;

int main(){

const int thisIsConstant = 10;

thisIsConstant = 9;

cout << thisIsConstant << endl ;
return 0;
}

error C2166: l-value specifies const object

gördüğünüz gibi l-value ( left value ) bir const nesneye işaret ediyor dedi derleyicim. Bunun anlamı sen atama yapamazsın çünkü sol da bir const değişken var, nereye atama yapıon sen filan diyor :)

ama derleyiciye sezdirmeden bu const değişkeni değiştirebiliriz... Değiştirdikten sonra bir soru sorucam bilene benden bi çikolata:)

işte değiştiriyoruz const değişkeni:
#include<iostream>
using namespace std;

int main(){

int* ptr;
const int thisIsConstant = 10;

ptr = ( int* ) &thisIsConstant; //cast ediyoruz

*ptr = 9; //degistirdikkkk

cout << thisIsConstant << endl;
return 0;
}

Evet thisIsConstant değişkenin bellek gözünde 9 mu yazıyor dersiniz??? Benim sistemimde ekran çıktısı:
10
Press any key to continue

10 yazıyor! Bunun sebebi, derleyicinin object kodunu oluştururken thisIsConstant değişkeni gördüğü yerleri değeriyle değiştirmesidir, derleyici kodda bu değişkenin değerinin 10 olduğunu ve const tanımlandığını görünce nasolsa bu const değişken değişemez diyip değerini object koda gömdü. ( Systems programming ders1 : studying assembly language provides; deeper understanding how the compiler works! )
Bu arada merak ediyosanız, debug yaparak değişkenin içeriğine baktığınız da ( ben baktım :) ) içerisinde 9 yazdığını göreceksiniz. Ama object kodda değişkenin kullanıldığı yerde değişkenin adresi değil derlendiği anda ki içeriği yani 10 değeri olduğu için aslında
cout << thisIsConstant << endl; satırı
cout << 10 << endl;
satırı ile yer değiştirmiştir ;) Derleyicim VS 6.0, başka derleyiciler de derlediğiniz zaman bu optimize yapılmıyorsa ekran da 9 sayısını görürsünüz. Mesala ben bu denemeden sonra, cpp uzantılı dosyayı c olarak değiştirdim, tabi iostream i de stdio ile

#include<stdio.h>

int main(){

int a = 5;
int* ptr;
const int thisIsConstant = 10;

ptr = ( int* ) &thisIsConstant; //cast ediyoruz

*ptr = 9; //degistirdikkkk

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

return 0;
}

işte ekran çıktısı:
9
Press any key to continue

Demek ki neymiş efendim, vs 6.0 da C ve C++ derlenirken kodun optimize edilişi farklıymış.

Aynı kodları, ssh ile itu ye bağlanip gcc ile derledim.
Sonuçlar:
C kodu için ekrana 9 değeri bastı,
C++ kodu için ekrana 10 değeri bastı.

Buradan genelleme yaparsak, C++ derleyicileri kodu optimize ederken, const değişkenlerin değerlerini object koda direk gömerler. C derleyicileri değişkenlerin adresilerini kullanmaya devam ederler. ( En azından VS 6.0 ve Gcc/G++ öle yapıo ).

Const değişkenler ve pointerlar hakkında söylenecek bayağı bir şey var aslında,
mesala;
const int* ptr ile int* const ptr nin farklı şeyler olduğunu biliyor muydunuz?

const int* ptr ; ile işaretçinin içeriğini değiştirebilirsiniz ama işaret ettiği verinin içeriği değişemez.

int x, y;
const int* ptr = &x ; //işaretçi oluşturulurken değer atanıyor OK
*ptr = 111; //işaretçinin gösterdiği yerdeki veri değişemez, HATA
ptr = &y; //işaretçi farklı bir değişkene işaret ettirildi, OK

int* const ptr; de ise işaretçinin işaret ettiği adres değişemez, ama içerdiği veri değişebilir:

int x,y;
int* const ptr = &x ; //işaretçi oluşturulurken değeri atandı, OK
*ptr = 111; //işaretçinin verisi değiştirilebilir OK
ptr = &y; //işaretçi const tanımlanmıştı, başka bir yere işaret edemez, HATA

Son olarakta const int* const ptr; ile tanımlanmış bir işaretçinin ne içerdiği veri, ne de gösterdiği yer değişebilir. ( yukarıda ki iki işaretçinin birleşimi gibi )

Bu yazımda da sizlerle birlikte const değişkenleri/işaretçileri tartışmış olduk.
Bir sonra ki yazımda C++ da convert constructor larla ilgili ilginç bir konuya değinmek istiyorum inşallah:) Görüşmek üzere...

4 comments:

Anonymous said...

anacım sanki trt4 açıköğretim programı gibi veda etmişsin yazına bu ne böle:)

Unknown said...

const_cast bile değiştiremedi, pes ediyorum..


#include<iostream>
using namespace std;

int main(){

int* ptr;
const int thisIsConstant = 10;

volatile int &ptr_s = const_cast<volatile int&>(thisIsConstant); // safe const cast


ptr_s = 9; //degistirdikkkk

cout << thisIsConstant << endl;
return 0;
}

Sonuç : yine 10

Anonymous said...

Veee oldu, c++ volatile declare etmeni beklermiş...

#include<iostream>
using namespace std;

int main(){

int* ptr;
volatile const int thisIsConstant = 10;

int &ptr_s = const_cast<int&>(thisIsConstant); // safe const cast


ptr_s = 9; //degistirdikkkk

cout << thisIsConstant << endl;
return 0;
}


erturkdiriksoy.wordpress.com

emreknlk said...

evet ertürk volatile değişkenler:) Bu vesileyle volitele ne demek onu da açıklayalım: volatile değişkenler kodda değeri her an, external bir process yada bir kesme tarafından değiştirilebilecek değişkenler için tanımlanır. Derleyici bu değişkenleri optimize etmez, bu yüzden object kodda da değişkenin değerini direk koda gömmüyor. Örneğin için teşekkürler:)