C Programlama diliyle şamatalar

Başlatan z, 23 Ekim 2011, 15:32:04

muhittin_kaplan

biraz açarmısın hocam konuyu incelikleri nedir

elektronikhobi

Alıntı Yapint *P;
P=(int*) 0x42345678;

Alıntı Yap
*P=0x12345678;
Alıntı yapılan: -Hasan- - 20 Ocak 2012, 14:02:11
Merhabalar;
Pointer konusunda anlamadığım bir şey var; yukarıdaki int ' lerin manasını anlayamadım:

(birisi bu gösterici 32 bitlik adres gösterebilir, birisi de buraya 32 bit tam sayı yüklenebilir demek mi yoksa?)


Aslında bu iki satır birleştirilerek yazılabilir.

int *p = (int *) 0x42345678;


Bu ilk iki satırda 2 şey gerçekleşiyor.

1) p'nin 'int*' olarak tanımlanması. p senin de tahmin ettiğin gibi 32 bitlik bir tamsayı göstergesidir.

2) p'ye ilk değer atanması. p'nin değeri 0x42345678 dir. p göstergesi 0x42345678 adresindeki tamsayıya 'int' işaret etmektedir.

İlk verdiğin koddaki gibi p'yi ilk değersiz bırakmak yerine ona 0 veya NULL ile ilk değer vermek daha iyidir.
int *p;   // <-- KOTÜ; çünkü p'nin değeri belirsiz; yanlışlıkla kullanırsak HATA!
	p = (int *) 0x42345678;


Tanımladığımız yerde uygun bir ilk değer yoksa onu 0'la ilklendiririz.
int * g = 0;  
	/* ... */
	// daha sonra:
	g = &bir_int;


En son satırdaki artık bir gösterge tanımladığımız için göstergenin gösterdiği anlamına geliyor. Yani göstergenin gösterdiği int tamsayısına bir değer ata anlamına geliyor.  0x42345678 adresindeki tamsayıya  0x12345678 değerini atıyoruz.

*p = 0x12345678; // göstergenin gösterdiği eşittir 0x...




berat23

Alıntı yapılan: -Hasan- - 20 Ocak 2012, 14:02:11
Merhabalar;
Pointer konusunda anlamadığım bir şey var; yukarıdaki int ' lerin manasını anlayamadım:

Bu int ne demek?
Bu int ne demek?

(birisi bu gösterici 32 bitlik adres gösterebilir, birisi de buraya 32 bit tam sayı yüklenebilir demek mi yoksa?)

aslında hepsi aynı boyutta adres gösterir.sadece gösterdiğinin boyutu hakkında bir bilgi vardır.

bu bir dizi üzerinde çalışırken anlaşılabilecek bir konu.diyelim dizi 32bitlik int elemanlaran oluşuyor,ilk elemanının adresini pointer ile gösterdik.

int dizi[50];
int *sPtr;


hafızada 50*4 bytelık bir alanı dizi için ayırdık ve int gösterecek bir pointer tanımladık.diyelim adreste 32 bit ,misalen dizinin başlangıç adresi 0x12F0 olsun(adres bus 16 bit olsun data ile karışmasın diye)

hafıza
0x12f0  -> dizi[0]
0x12f4  ->dizi[1]
..
..



sPtr=dizi;


bu kod ile sPtr=0x12f0 ile yüklenir,*sPtr ise dizinin ilk elemanıdır.

diyelim sıralı bir işlem yapılacak.eğer sPtr yi bir arttırırsak 32 bitlik bir ing gösterdiği için değeri 4 byte artar,0x12f4 olur.normalde +1 olunca 0x12f1 olması beklenir aritmetik olarak ama gösterdiği değer int olduğundan dolayı (kapladığı alandan dolayı) böyle olur.yani verinin türünün tanımlanması buna yarar.umarım anlatabilmnişmdir.

okylmz

Alıntı yapılan: z - 27 Ekim 2011, 01:06:42

pointeri isaretli de tanimlasaniz isaretsiz de tamislasaniz 0xFFFFF000 yazdinizmi porttan 0xFFFFF000 cikar. Sorun okumada.

Asağıdaki proğram parçacıgı porttaki 0x80000000 verisini okuyup sağa kaydırıp tekrar porttan çıktığında porta yazilan veri 0xC0000000 olacaktır.

Halbuki pointeri unsigned int tanımlasaydık porttaki 0x80000000 verisini okuyup sağa kaydırıp tekrar porttan çıktığında porta yazılan veri 0x40000000 olacaktı.

#define Reg  (*((int*) 0x42345678))

      Reg=Reg>>1;

Aksi takdirde her defasinda type casting yapmak gerekirdi.

Peki aşagıdaki satirda neden volatile ön eki getirme ihtiyacı duyarız?

#define Reg  (*((volatile unsigned int*) 0x42345678))

bu başlığın 8. sayfasına geldim ve şurada takıldım, bilen birisi açıklayabilir mi acaba;

*Halbuki pointeri unsigned int tanımlasaydık porttaki 0x80000000 verisini okuyup sağa kaydırıp tekrar porttan çıktığında porta yazılan veri 0x40000000 olacaktı <-----> bu kısmı anladım

*Asağıdaki proğram parçacıgı porttaki 0x80000000 verisini okuyup sağa kaydırıp tekrar porttan çıktığında porta yazilan veri 0xC0000000 olacaktır. <-----> burasını anlamadım 0x80..... verisi bir sağa kayarsa neden 0xC0....olur?

teşekürler...

z

Eger isaretli bir degisken tanimladiysak bu degiskende pozitif yada negatif sayilar saklayabiliriz.

Negatif sayilar icin 2 ye tumleyen modu kullaniliyor. Bu gosterim seklinde en yuksek konumdaki bit isaret bitidir.

Ornegin 8 bit icin 0x80 hex sayisi decimal -128 demek. Bunun yarisi 0xC0 hex sayisi ise decimal -64 demek.

Isaretli sayilar aritmetik olarak saga kaydiriliyorsa isaret biti aynen yerinde kalir isaret biti dahil saga kaydirilir.


Bana e^st de diyebilirsiniz.   www.cncdesigner.com

okylmz

Alıntı yapılan: z - 03 Mart 2012, 10:10:02
Eger isaretli bir degisken tanimladiysak bu degiskende pozitif yada negatif sayilar saklayabiliriz.

Negatif sayilar icin 2 ye tumleyen modu kullaniliyor. Bu gosterim seklinde en yuksek konumdaki bit isaret bitidir.

Ornegin 8 bit icin 0x80 hex sayisi decimal -128 demek. Bunun yarisi 0xC0 hex sayisi ise decimal -64 demek.

Isaretli sayilar aritmetik olarak saga kaydiriliyorsa isaret biti aynen yerinde kalir isaret biti dahil saga kaydirilir.

cevap için teşekür ederim @bunalmış.
8. sayfadan devam ediyorum.

okylmz

Alıntı yapılan: gerbay - 22 Aralık 2011, 23:55:39
1. soru için;

Hocam bu tür şeyleri en iyi anlamanın yolu kodu yazıp üretilen kodu ya da preprocessor output dosyasını incelemektir. Şöyle ki;

GPIOD->OSPEEDR= 0xFFFFFFFF;

kodunda GPIOD ve OSPEEDR var ve "->"  'point' işareti ile bir pointer erişimi olduğu belli. Şimdi GPIOD ve OSPEEDR neymiş ona bakmak lazım;

GPIOD yi ilgili header larda ararsanız şöyle bir tanım bulursunuz;

#define GPIOD               ((GPIO_TypeDef *) GPIOD_BASE)

burada yine bilinmeyenler var. GPIOD_BASE e de bakalım;

#define GPIOD_BASE            (AHB1PERIPH_BASE + 0x0C00)

karşımıza AHB1PERIPH_BASE çıktı birde, onun tanımı;

#define AHB1PERIPH_BASE       (PERIPH_BASE + 0x00020000)

PERIPH_BASE in tanımı ise;

#define PERIPH_BASE           ((uint32_t)0x40000000)

yani interpret ederseniz GPIOD_BASE şöyle oluyor;

((uint32_t)0x40000000 + 0x00020000 + 0x0C00)

GPIOD ise;

((GPIO_TypeDef *) 0x40020C00)
   
şeklinde birşeye dönüşüyor. Yani memory mapped IO da GPIO-D portunun base adresini işaret ediyor.
   
O base adresten itibaren offset ler de GPIO_TypeDef tanımı içerisinde var. Şöyle ki;

/** 
  * @brief General Purpose I/O
  */
typedef struct
{
  __IO uint32_t MODER;    /*!< GPIO port mode register,               Address offset: 0x00      */
  __IO uint32_t OTYPER;   /*!< GPIO port output type register,        Address offset: 0x04      */
  __IO uint32_t OSPEEDR;  /*!< GPIO port output speed register,       Address offset: 0x08      */
  __IO uint32_t PUPDR;    /*!< GPIO port pull-up/pull-down register,  Address offset: 0x0C      */
  __IO uint32_t IDR;      /*!< GPIO port input data register,         Address offset: 0x10      */
  __IO uint32_t ODR;      /*!< GPIO port output data register,        Address offset: 0x14      */
  __IO uint16_t BSRRL;    /*!< GPIO port bit set/reset low register,  Address offset: 0x18      */
  __IO uint16_t BSRRH;    /*!< GPIO port bit set/reset high register, Address offset: 0x1A      */
  __IO uint32_t LCKR;     /*!< GPIO port configuration lock register, Address offset: 0x1C      */
  __IO uint32_t AFR[2];   /*!< GPIO alternate function registers,     Address offset: 0x20-0x24 */
} GPIO_TypeDef;

bu structure tanımında OSPEEDR yi de bulduk. Offset adresi olarak 0x08 adresinde. Base adres üzerine OSPEEDR için offset adresini de ilave edeceğiz. Bu durumda kodumuzdaki;
   
GPIOD->OSPEEDR = 0xFFFFFFFF;

kısmı şuna dönüşüyor; özellikle OSPEEDR nin tip tanımına dikkat;

*((__IO uint32_t*) 0x40020C08 ) = 0xFFFFFFFF;
   
yani memory de ki 0x40020C08 adresine 0xFFFFFFFF değeri atanıyor..
   
Zaten preprocessor dosyası üretip incelerseniz derlenmeden önce kodun preprocess aşamasında
   
((GPIO_TypeDef *) ((((uint32_t)0x40000000) + 0x00020000) + 0x0C00))->OSPEEDR= 0xFFFFFFFF;

şeklinde dönüştürüldüğünü görürsünüz.
   
derlenmiş kodda da göreceğiniz kod şudur;

kaynak kod:

int main()
{
  GPIOD->OSPEEDR= 0xFFFFFFFF;

  for (;;);
}

üretilen kod:

.text:00000008                                EXPORT main
.text:00000008                main
.text:00000008 02 49                          LDR     R1, =0x40020C08 
.text:0000000A 4F F0 FF 30                    MOV.W   R0, #0xFFFFFFFF ; Rd = Op2
.text:0000000E 08 60                          STR     R0, [R1]        ; Store to Memory
.text:00000010
.text:00000010                loc_10                                  ; 
.text:00000010 FE E7                          B       loc_10          ; Branch
.text:00000010                ; End of function main
.text:00000010
.text:00000010                ; ---------------------------------------------------------------------------
.text:00000012 00 00                          ALIGN 4
.text:00000014 08 0C 02 40    dword_14        DCD 0x40020C08          ; DATA XREF: mainr

açıklama;

ilk satırda R1 registerına 0x40020C08 değeri aktarılıyor.. tam olarak GPIO-D nin OSPEEDR registerının adresi,
ikinci satırda R0 registerına 0xFFFFFFFF değeri aktarılıyor,
üçüncü satırda ise R0 da bulunan değer R1 ile işaret edilen adrese yazılıyor..
   
olay bundan ibaret..
@gerbay emeğine sağlık çok güzel bir cevap hazırlamışsın.
kendi adıma söylüyorum; kafamda bir sürü sorunun cevbaını bulmuş oldum.
keilde projenin içindeki dosyaları kurcalarken, orada yazılanların artık yabancısı olmam.
teşekürler...

eraygil

mrb arkadaşlar bende bu stm32f4-discovery kartını yeni aldım formu sürekli takip ediyorum ama kafam bayağı karıştı daha önce ccs c ile program yazıyordum bu çok farklı geldi bana ya da olayın özünü anlayamaış olmamdan da kaynaklanabilir. örneğin size şöyle bir soru soracağım

while(TRUE)
{
output_b(0xff);
delay_ms(1000);
output_b(0x00);
delay_ms(1000);
}

acabaa bu tip komutlarla keilde program yazamazmıyız.

M_B

merhaba
CCS ye yakın program yazabılmen ıcın
http://www.st.com/internet/evalboard/product/252419.jsp linkinden
FIRMWARE  indirip bu kutuphaneyi kullanman gerekir.

Ornek:


GPIO_InitTypeDef GPIO_InitStructure;
static __IO uint32_t TimingDelay;


void Delay(__IO uint32_t nTime);

  uint8_t k,l;

int main(void)
{

   
   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);    
        SysTick_Config(SystemCoreClock/ 1000);


    GPIO_SetBits (GPIOE, E);
    GPIO_ResetBits (GPIOE,E);

void init_port (void)
{   
   GPIO_InitTypeDef  GPIO_InitStructure;    
    RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOE | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD    , ENABLE);


   GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15;
   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
   GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_OUT;

  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
   GPIO_Init(LCD_PORT, &GPIO_InitStructure);

.......
gibi..

İmkanın sınırlarını görmek için imkansızı denemek lazım.                                                             Fatih Sultan Mehmet

eraygil

ilgin için teşekkürler mb  neyse bu daha karmaşık diğeri daha anlaşılır  :(

Engineer Jr.

int *p;
p=(int*) 0x42345678;  
*p=0x12345678;


Bu şekilde bir kullanımda 0x42345678 adresindeki bir register a 0x12345678 değeri atıyoruz tamam. Anlamadığım kısım neden "p=(int*) 0x42345678; " ifadesinde (int*) parçasına ihtiyaç duyuyoruz.

Integer tipinde bir pointer tanımladık, neden bu pointer a direk olarak "p=0x42345678;" şeklinde adresini veremiyoruz ? 

Tagli

Veremiyor muyuz? Denemedim ama bana sanki verebilirmişiz gibi geldi. Derleyici hata veriyorsa eğer bunun sebebi olası mantıksal hataları derleme anında bulabilmek içindir. Yani senin ne yaptığının farkında olmanı istiyor olabilir.

Ama bence kendin 0x42345678 gibi rasgele bir adres tanımlayamazsın. Adresler önceden tanımlı değişkenlerden veya malloc() gibi fonksiyonlardan gelmeli.
Gökçe Tağlıoğlu

Erdem

Alıntı yapılan: Engineer Jr. - 08 Haziran 2012, 05:44:02
Anlamadığım kısım neden "p=(int*) 0x42345678; " ifadesinde (int*) parçasına ihtiyaç duyuyoruz.

Integer tipinde bir pointer tanımladık, neden bu pointer a direk olarak "p=0x42345678;" şeklinde adresini veremiyoruz ?

Çünkü dikkat ederseniz göstergenin türü int* dir. Direkt olarak göstergeye o değeri veremeyiz çünkü göstergenin türü int* sağ taraftaki değer int olduğu için hata verecektir.

İkinci kullanımda da göstergenin önüne gelen asteriks işareti göstergenin gösterdiği anlamına gelmektedir. Yani *gosterge gibi .. Göstergenin gösterdiği değer de bir tamsayı olacağı için burada bir sıkıntı yok.

Ancak ilk kullanımda 0x42345678 adresinin geçerli bir bellek adresi olduğunu biliyormuyuz. Eğer bu adres geçerli bir bellek adresi değilse programımız hatalı olacaktır.

Engineer Jr.

Evet şu an çok fena dank etti desem yeridir :) int tipinden int* tipine bildiğimiz type casting yapıyoruz. Pointer a int tipi atarsak olmayacaktır elbette. Bunu okudğum sırada saat sabaha karşı bir vakitti artık beyin ne kadar sulanmışsa : D

yamak

#299
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
unsigned char* fonk(unsigned const char* const str1,unsigned const char* const str2)
{
    unsigned char* temp=(unsigned char*)(malloc(strlen(str1)+strlen(str2)+1));
    memcpy(temp,str1,strlen(str1));
    memcpy(temp+strlen(str1),str2,strlen(str2));
    return temp;
}

int main(void)
{
    unsigned char* addr;
    unsigned const char *str1 =(unsigned char*)"yusuf ";
    unsigned const char *str2 =(unsigned char*)"YAMAK";

    addr=fonk(str1,str2);
    printf("%s\n",addr);
    free(addr);
    return 0;
}


Böyle bi programda eğer printf() 'ten sonra free kullanmazsam stack te ayrılmış olan yer yine boşalmış olur mu? Bu soruyu sormamın nedeni bildiğiniz gibi fonksiyon içindeki değişkenler normalde dinamik ömürlü oluyo. tamam temp değişkeni siliniyordur. ama temp in gösterdiği adres tekrar serbest bırakılıyo mu?