CCS C'de pointer kullanımı

Başlatan 50Cal, 23 Haziran 2010, 14:00:58

50Cal

Merhaba, 2 gündür pointer kullanımıyla ilgili konulara, örneklere bakıyorum fakat daha işin en temel kısmını net bir şekilde açıklayan bir kod örneği yada bilgi bulamadım.

Nedir bu anlamaya çalıştığım temel..

*ptr şeklinde bir pointer tanımladıktan sonra program içerisinde *ptr dediğimizde veya ptr dediğimizde bunlardan hangisi adresi içeriyor hangisi o adresteki bilgiyi içeriyor?

Olabilecek en basit koda bakıyorum ama yok yine kafam karışıyor, biri aşağıdaki kodaların yanına ne yapıldığını yazabilirse çok sevinirim.

char *k;     // bundan sonra pointerım k mı *k mı? bu satır işlendiği anda picte olan olay nedir tam olarak?
k=(char *) 0x2A03;   //burada (char *) ifadesi neden kullanılıyor? ne demek? zaten pointerı tanımlarken göstereceği adresteki bilginin char türünde olduğunu belirtmişim
*k='b';  // bu işlemle, b karakterini pointera mı atıyoruz yoksa pointerın gösterdiği adrese mi? bildiğim kadarıyla *k pointer oluyor...

Şu üç satırda pic'te tam olarak ne olup bittiğini öğrenmek istiyorum. Pointerın adresi,içeriği ve pointerın gösterdiği adres ve içeriği nasıl değişiyor?

(forumda nette ve kitapta baya bir araştırdım ama "for dummies" tadında bir anlatıma ihtiyacım var, bu pointerı anlayabilmek için..)

JKramer

#1
Alıntı yapılan: 50Cal - 23 Haziran 2010, 14:00:58
*ptr şeklinde bir pointer tanımladıktan sonra program içerisinde *ptr dediğimizde veya ptr dediğimizde bunlardan hangisi adresi içeriyor hangisi o adresteki bilgiyi içeriyor?
ptr adresi, *ptr ise o adresteki bilgiyi içeriyor.

İçerik                                     -->5         
Değişken                               -->sayi
Değişkenin bulunduğu adres -->0xA

int8 sayi=5;
int8 *ptr;

ptr=&sayi; // ptr'de sayi değişkeninin adresi var artık


Ekrana ptr'yi yazdırırsanız 0xA yani sayi değişkeninin adresini görürsünüz.
Ekrana *ptr'yi yazdırırsanız 5 yani sayi değişkeninin içeriğini görürsünüz.

int8 sayi=5;
int8 yas=13;
int8 *ptr;

ptr=&sayi; // şu anda ptr=0xA, *ptr=5, sayi=5, yas=13
yas=*ptr; // şu anda ptr=0xA, *ptr=5, sayi=5, yas=5

yas=33; // şu anda ptr=0xA, *ptr=5, sayi=5, yas=33
ptr=&yas; // şu anda ptr=0xCD, *ptr=33, sayi=5, yas=33 (yas değişkeninin adresi 0xCD olsun) 
sayi=*ptr; // şu anda ptr=0xCD, *ptr=33, sayi=33, yas=33


Düzenleme: *ptr=33 düzeltmesi. Hemen öğrenmişsiniz :).

50Cal

Çok teşekkürler, çok güzel açıklamışsınız :)

Yalnız şu satırda(sondan 2. satır), *ptr=33 olması gerekiyor sanırım..
ptr=&yas; // şu anda ptr=0xCD, *ptr=5, sayi=5, yas=33 (yas değişkeninin adresi 0xCD olsun)

ve 1 diğer sorum da;
ilk mesajımdaki o 3 satırlık kodda, 2. satırda k=(char *) 0x2A03; neden (char *)ifadesi kullanılmış? bu kullanılmasa da zaten program k pointerının tutacağı adres içeriğinin "char" türünde olduğu 1. satırda öğrenmiş olmuyor mu?
(char *) ifadesi burada ne amaçla kullanılmıştır, ne işe yaramıştır?

JKramer

Alıntı yapılan: 50Cal - 23 Haziran 2010, 14:48:22
...bu kullanılmasa da zaten program k pointerının tutacağı adres içeriğinin "char" türünde olduğu 1. satırda öğrenmiş olmuyor mu?
(char *) ifadesi burada ne amaçla kullanılmıştır, ne işe yaramıştır?

Evet, derleyici birinci satırda k pointer'ının tutacağı adres içeriğinin "char" türünde olduğunu öğreniyor. Ancak bu pointer'a atama yaparken (char *) diyerek "cast" işlemi yaparsak sadece kendi tipinde atama yapmasını sağlamış oluruz. Float sayılarla ilgili bir örnek verelim:

int8 a=0;
float b=32.675;

a=(int8) b; //b'nin sadece tam kısmını aldık, a=32


Eğer a ve b aynı tipte olsaydı cast etmemize gerek yoktu. Yalnız pointer'larla ilgili v4104 de ansi uyumluğu için bir değişiklik yapılmış sanırım, kurulum klasörünün altındaki readme.txt dosyasına bakarsanız;
Alıntı YapUsers that have old code with expresions of the form:
            *(&data + i)
need to change them to:
            *((int8 *)(&data) + i)
A compiler change was made to be ANSI compliant.

Anladığım kadarıyla pointer'larla işlem yaparken cast etmemiz gerekiyor.

picmanya

0X2A03; yazımı işaretli veya işaretsiz int değerinde bir değerdir.
bunun önüne  (char*) yazarak bu değişkeni işaretçi char tipli olarak k değişkenine atıyor derleyici ayarları uygun değilse bunu yazmak çok önemli zaten bu durumda yazılmalıda standart C mantığı oluyor bu
yazılmazsa  k değişkenin içeriği kapasite aşımından dolayı abudik gubidik istenmeyen bir değer alır.

yanlış bilmiyorsam sizin derleyicide işaretçi tanımlaması zaten int değerinde alan ayrımı ile yapılıyor char tipli işaretçi içinde int alan ayrılıyor.mantık böyleyken char işaretçi tanımı çok mantıklı değil aslında.

50Cal

#5
Çok teşekkürler cevaplarınız için. Şu char* kullanımına dair aklımda bir kaç soru var hala, en iyisi akşam eve döndüğümde proteus debug'dan  bir incelemek olacak k'nın içeriğini.



Bu kısımda çok seri saçmalamış gitmişim, şimdi farkettim..
Stringler insanlar içindir, makina niye hamallık edip de bir sayıyı kendisi için karakter olarak kaydetsin değil mi :)
Berrak beyinler bulanmasın başka kafalar karışmasın diye de sansür koydum sabahki demecime..


Gökhan BEKEN

Pic için pointer kullanmak ne gibi  kolaylık sağlar?
Özel mesaj okumuyorum, lütfen göndermeyin.

radres


radres

0x2A03 değerinde 2A değeri 8 bit (00101010), 03 değeri 8 bit (00000011). Toplam 16 bit. Böylece 8 bitlik bellek yapısına sahip bir mikroişlemcide bu değer iki adet 8 bitlik bellek alanında saklanır. Toplam 2 byte.

M_B

Merhabalar
volatile uint8_t*  OWDDR;
Bu pointer dışında farklı şeymi?.
Pointer desem
volatile uint8_t   *OWDDR; şeklinde olması lazım.

Kitapları karıştırdım ama bu şekilde yazılanı gormedim.
Orneğin tamamı alt kısımda.


#ifdef OW_ONE_BUS

#define OWPORT_IN()   	( *OWPIN & (1<<PIN) )
#define dir_in()   		( *OWDDR &= (~(1<<PIN) ) ) //input
#define dir_out()  		( *OWDDR |= (1<<PIN) ) // output
#define OWPORT_LOW() 	( *OWPORT &=(~(1<<PIN)) )
#define OWPORT_HIGH() 	( *OWPORT |=(1<<PIN) )

#else
/* set bus-config with ow_set_bus() */
uint8_t OW_PIN_MASK; 
volatile uint8_t* OWDDR;
volatile uint8_t* OWPORT;
volatile uint8_t* OWPIN;
İmkanın sınırlarını görmek için imkansızı denemek lazım.                                                             Fatih Sultan Mehmet

JKramer

#10
Alıntı yapılan: 50Cal - 23 Haziran 2010, 15:46:31
Çok teşekkürler cevaplarınız için. Şu char* kullanımına dair aklımda bir kaç soru var hala, en iyisi akşam eve döndüğümde proteus debug'dan  bir incelemek olacak k'nın içeriğini.

yalnız, çıkmadan size de sorayım aklımdakini:

- k adres bilgisini tutan bir değişken
- k'nın içerisinie 0x2A03 adres bilgisini(yani "0x2A03" şeklinde string bir ifade) char türünde atıyoruz
- bu işlemin ardından her bir "karakter"in 1 byte yer tuttuğunu düşünürsek, k değişkeni bellekte 6 byte yer tutmaktadır..


şeklinde düşündüm, yanılıyor muyum?

int8 *ptr; dediğimizde bunun anlamı "pointer to int8" dir. Yani bu pointer, int8 tipindeki bir değişkene işaret edebilir. Sanırım sizin kafanız pointer'ın hafızada kapladığı yerle ilgili karışmış. Bir pointer'ın hafızada kapladığı yer sabittir. CCS'de 8 bitlik mikrodenetleyiciler için bir pointer, varsayılan olarak 8 bit'lik, 16 bit'lik mikrodenetleyiciler için de varsayılan olarak 16 bit'dir. Eğer biz 8 bit'lik bir mikrodenetleyicide 16 bit'lik pointer kullanmak istiyorsak;

#device *=16


yazmamız gerekir. Derleyicinin yardım dosyasında yazan, #device altında kullanılabilecek diğer seçenekler şöyle:
Alıntı Yap*=5
Use 5 bit pointers (for all parts)

*=8
Use 8 bit pointers (14 and 16 bit parts)

*=16
Use 16 bit pointers (for 14 bit parts)


k pointer'ına adres bilgisini karakter olarak değil, sayı olarak atıyoruz. Sonuç olarak, sizin örneğinizdeki gibi 8 bit'lik bir pointer olan k'ye 0x2A03 gibi 16 bit'lik bir adres atamayız. (Kullanılan mikro denetleyicinin 8 bit'lik ve #device *=16 yazılmadığını varsaydım.)

@M_B

Asteriskin yeri önemli değil, pointer yani.

50Cal

@JKramer
Pointerın bellekte kapladığı alan konusunda saçmalamışım, çünkü o 2. satırda pointerın adres bilgisi char türünde kaydediliyormuş gibi algıladım(özrün kabahate fark atması da böyle birşey :) )
O konuda bir soru kalmadı kafamda...

Fakat; (char *) kullanımı ile ilgili, proteus debugdan kontrol ederek bazı denemeler yaptığımda, mesela o 3 satırlık kodda (char *) varken de yokken de aynı sonuç oluyor, işlemde bir fark yok.(tabi kullandığım ccs versiyonuyla ilgili de olabilir. 4.016 sürümü)

Bahsettiğiniz float örneğini de denedim; float bir sayıyı, int olarak tanımlanmış değişkene yüklemeyi denedim olmadı. int olarak tanımlanmış bir pointer ile yapmayı denedim yie olmadı. Yani float sayıyının tam kısmı da gelmiyor o integerin içine başka bir değer de gelmiyor. o değişken sürekli boş görünüyor debugda..

Ama benim asıl kaldığım yer şu 2. satır. oraya tam olarak ne yapıldığını yazamıyorum. çünkü 2. satırdaki işlem *k'ya değil k'ya(yani adrese) yönelik yapılan bir işlem. işte bunu düşününce tekrar başa dönüyorum ve şunu diyorum "k adres bilgisi, sayısal bir değer yani hafızadaki 256 adresten birisi(30 olur 130 olur..) bunun char ile ne ilgilisi var?"

char *k;     // k nın gösterdiği adresteki veri, karakter türündedir..
k=(char *) 0x2A03;   // ???
*k='b';


JKramer

#12
Alıntı Yapk nın gösterdiği adresteki veri, karakter türündedir..
Aynen dediğiniz gibi. Biz bir pointer tanımlarken char *k; satırındaki tip belirttiğimiz 'char', pointer'ın tipini değil, gösterdiği yerdeki değişkenin tipini belirler. Yani biz pointer'ın tip tanımlamasını yaparken, o pointer'ın gösterdiği değişkenin tipini dikkate alırız.

Sizin örneğinizdeki pointer 'b' karakterini gösterecekse k pointer'ını 'char' olarak tanımlarız. Eğer pointer 16 bit'lik bir değişkeni gösterecekse k pointer'ını int16 şeklinde tanımlarız. Bunların pointer'a atayacağımız adres bilgisinin büyüklüğüyle bir ilgisi yok. Pointer'ın temelde gösterebileceği 'adres' en fazla 0xFF olabilir(8 bit'lik pointer). 
Alıntı yapılan: 50Cal - 23 Haziran 2010, 23:51:43

Fakat; (char *) kullanımı ile ilgili, proteus debugdan kontrol ederek bazı denemeler yaptığımda, mesela o 3 satırlık kodda (char *) varken de yokken de aynı sonuç oluyor, işlemde bir fark yok.(tabi kullandığım ccs versiyonuyla ilgili de olabilir. 4.016 sürümü)

Yanlış hatırlamıyorsam aritmetik işlemlerde o cast işlemini yapmazsanız sorun çıkıyordu. Örneğin üç tane pointer tanımlayıp adres bilgilerini toplayıp çıkarın, bir de cast ederek yapın. Ben daha önceki denemelerimi bulabilirsem inceleyip buraya eklerim.
Alıntı yapılan: 50Cal - 23 Haziran 2010, 23:51:43
Bahsettiğiniz float örneğini de denedim; float bir sayıyı, int olarak tanımlanmış değişkene yüklemeyi denedim olmadı. int olarak tanımlanmış bir pointer ile yapmayı denedim yie olmadı. Yani float sayıyının tam kısmı da gelmiyor o integerin içine başka bir değer de gelmiyor. o değişken sürekli boş görünüyor debugda..

#include <16F628A.h>

#use delay(clock=4000000)

#fuses NOWDT
#fuses PUT
#fuses NOMCLR
#fuses BROWNOUT
#fuses NOLVP
#fuses CPD
#fuses PROTECT
#fuses INTRC_IO

void main()
{
   for(;;)
   {
      float x=32.65;
      int8 y=0;
      y=(int8)x;
   }
} 


Proteus'da debug ederken PIC CPU Variables altında, her bir değişkenin karşısındaki 'value' değerine sağ tıklayıp tipini seçmeyi unutmayın:

[IMG]http://i46.tinypic.com/2di0v12.jpg[/img]

Ekleme:

Bu da pointer'lı bir örnek:

#include <16F628A.h>

#use delay(clock=4000000)

#fuses NOWDT
#fuses PUT
#fuses NOMCLR
#fuses BROWNOUT
#fuses NOLVP
#fuses CPD
#fuses PROTECT
#fuses INTRC_IO

void main()
{
   for(;;)
   {
      float x=32.65;
      int8 y=0;
      float *ptr; //ptr, float tipindeki bir sayıyı gösterebilir
      ptr=&x; // float tipindeki x değişkeninin adresini ptr'ye at
      y=(int8)*ptr; //ptr'nin gösterdiği adresteki bilginin int8 kısmını al, y'ye at
      //y=(int8)x;


[IMG]http://i46.tinypic.com/n2d1tj.jpg[/img]

        Adres     Değer
x       0x21      32.65
y       0x25      32
ptr    0x26      0x21 (*ptr=32.65)

Görüldüğü gibi 8 bit'lik ptr'ye atadığımız adres 0x21, gösterdiği değişken ise float tipinde.

50Cal

Malum proteus sorunumdan dolayı tekrar deneyememiştim, dediğiniz gibi pointerlı pointersız her türlü yapılıyor tam kısmı alma olayı, ben debugta bi dikkatsizlik yapmışım..

Şimdi pointerla bir dizi adrese erişme olayına bakıyorum, mantık basit görünüyor ptr'ın değerini bir arttır bir sonraki adrese eriş. ama tabi malloc gibi bilmediğim komutları da inceliyip dinamik bellek yönetimini doğru düzgün anlamak istiyorum. Takıldığım yerlerde burdan sorarım tekrar.

Tabi eğer ccs'te dinamik bellek yönetimiyle ilgili, güzel kaynak biliyorsanız, oradan çalışabilirim. Genelde C üzerinden anlatılıyor bu konu ve ufak tefek farklılar kafamı karıştırmasın diye direkt ccs üzerinden anlatım arıyorum.

İlginiz için teşekkürler :)

EFESU

arkadaşlar kusura bakmayın  okuyunca anladım sandım sonra kod yazarken kafam biraz karıştı

PIC basıc  olarak anlatayım

X  VAR  BYTE 60  dediğimizde
x değişkeni 60 . adreste demek oluyor ve similasyonde felan kullanım takip  mükemmel oluyor.

tanımladığımız değişken adresini bi znasıl vereceğiz ccs c de .. _?