C Header Function Protoype

Başlatan yldzelektronik, 02 Ağustos 2017, 13:14:36

yldzelektronik

C projelerinde zaman zaman birden fazla dosyalar üzerinde çalışmak durumunda kalabiliriz. Böyle durumlarda projeyi .h ve .c dosyalarına ayırmak okunaklılık ve bakım açısından büyük kolaylık sağlar.

C programlama dilinde fonksiyon kullanımı için, ilgili fonksiyonun prototip tanımlaması yapılması, kullanılmadan önce yapılmalıdır. Aksi takdirde bilinmeyen fonksiyon diye uyarı alınacaktır.

Bu tür durumlarda ortaya header dosyaları çıkar. Header dosyaları içinde ilgili fonksiyon prototip tanımları yapılır ve istenilen her dosyaya dahil edilebilir (#include "xxx.h" şeklinde).

Ancak header dosyaları ile ilgili bir kritik vardır. Eğer bir header dosyası birden çok yerde dahil edilecekse bu fonksiyonların birden çok kez tanımlanması anlamına gelir ve sizin bir kez tanımlayıp oluşturduğunuz fonksiyonlar, sanki her dahil edilmiş yerde aynı ad ile yeniden oluşturulmuş gibi muamele görürler.
Bu tür durumların önüne geçmek için ise bir macro ile çözüm üretilir.
Aşağıda örnek bir c ve header dosya yapısı mevcuttur.

com.c
#include <stdint.h>   /* uint8_t gibi tür tanımlarının bulunduğu dosya */
#include "com.h"       /* bahsi geçen örnek header dosyası */

/* @brief    Uart 1 üzerinden 1 byte veri okuyan fonksiyon
    @param  void
    @return  uint8_t 1 byte uart data
*/
uint8_t get_char_Uart( void )
{
   return Uart_ReadDataRegister( USART1 );
}

/* @brief    Uart 1 üzerinden 1 byte veri gönderen fonksiyon
    @param  uint8_t data gönderilecek data
    @return  void
*/
void put_char_Uart( uint8_t data )
{
   Uart_Send( USART1, data );
}


com.h
#ifndef __com_h
#define __com_h

/* @brief    Uart 1 üzerinden 1 byte veri okuyan fonksiyon
    @param  void
    @return  uint8_t 1 byte uart data
*/
uint8_t get_char_Uart( void );

/* @brief    Uart 1 üzerinden 1 byte veri gönderen fonksiyon
    @param  uint8_t data gönderilecek data
    @return  void
*/
void put_char_Uart( uint8_t data );

#endif


Fark edilirse, header dosyası içinde
#ifndef __com_h #define __com_h #endif
şeklinde bir ifade mevcut.
Bu ifade ile bu dosya ve içeriğinin tek bir kez oluşturulması garanti altına alınıyor.
Hatalı olduğum noktaları lütfen bildiriniz.Yanlış bilgilendirme yapmak istemem.
@muhittin_kaplan  @Cemre.  @mehmet
Kişinin başına gelen hayır Allah'tandır. Kişinin başına gelen şer nefsindendir. Nefislerimizle kendimize zulüm ediyoruz.

izturk

Konuyla alakalı başka başlık bulamadım. Bu konuyu hortlatayım dedim.


cube mx le projemi oluşturuyorum. bana bir main.h ve main.c oluşturuyor.
yukarıdaki gibi bir kutuphane.h oluşturuyorum. kutuphane.c oluşturmadan fonksiyonumu direk kutuphane.h içinde yazıyorum.


main.c içinde
#include "main.h"
#include "stm32f4xx_hal.h"
#include "kutuphane.h"




int deger=0;



kutuphane.h dosyasını include ettiğimde fonksiyonu main.c den çağırabiliyorum. Problem yok çalışıyor. Fonksiyonumun içinde hal kütüphensi fonksiyonlarını da kullanabiliyorum.


kutuphane.h
#ifndef kutuphane_fonk
#define kutuphane_fonk


void konum_degistir(uint16_t gecikme)
{
	  HAL_GPIO_TogglePin(GPIOD,GPIO_PIN_15);
		HAL_Delay(gecikme);
	
	deger++;
}
	


#endif



şimdi sorularıma geçiyim.
1. kutuphane.h içinde fonksiyon prototipini tanımlayıp kutuphane.c oluşturup fonksiyonu onun içine mi yazmam gerekir.
bunun faydası sadece düzenli olması mıdır, yoksa başka gereklilikleri var mıdır?
eğer böyle yapmak istersek main.c de kutuphane.h da ve kutuphane.c de başta hangi dosyaları include etmemiz gerekir. içinden çıkamadım.
2. yukarda verdiğim kutuphane.h içinde deger değişkenini 1 artırmak istediğimde hata alıyorum. kütüphane içinde main.c içindeki global değikenlere müdahale edemiyormuyuz. veya etmemiz için ne yapmak gerekir?

Cemre.

extern int deger; diye kutuphane içerisinde tekrar tanımlayabilirsiniz. Ya da fonksiyona parametre olarak değerin adresini geçersiniz ve ona müdahale edersiniz. Ben olsam ikincisini tercih ederdim.

izturk

Degiskenin adresini pointer kullanarak mi gececez yoksa baska sekilde mi cemre hocam kucuk bi ornek verebilirmisiniz

foseydon

1. sorunun devabi duzenli olmasi. belirli bazi teamuller var, bunlari uygulamak lazim. butun islevsellik ve data .c dosyalarina, butun tanimlama ve prototipler .h dosyalarina gitmeli bence.

2. soruna gelirsem, global kullanma. cemre'nin dedigi 1. secenegi yap. fonksiyona arguman olarak ver, bunu aliskanlik edin cok faydasini gorursun.

izturk

Eğer yanlış anlayıp farklı bişeyler denemediysem Cemre. hocamın söylediği iki yöntemi de denedim çalıştırdım.
kutuphane.c dosyasını da oluşturdum. fonksiyonlarımı onun içine yazdım. .h da sadece prototipleri belirttim.


şimdi iki sorum daha olacak.


1. #ifndef #define #endif i .h da kullandım. .c de de kullanılır mı gereklimidir.


2. bunu tek bir işlem yapacak bir fonksiyon olarak değil de programın herhangi bir parçasını bölmek istiyorum gibi düşünelim
örneğin programımda menü var menü çok fazla kod içeriyor. 40 50 adet ayar değişkenini lcd ve tuş takımı kullanarak değiştirecek ve kaydedecek.
bunu da aynı şeiklde kütüphane oluşturur gibi mi bölmek lazım. yoksa bunun farklı yolları var mı?
kütüphane gibi böleceksek bütün değişkenlerin adreslerini mi göndereceğiz.
ayarları bir dizide tutsak dizinin ilk elemanının adresini göndersek diğerleri illaki ardışık adreslerde mi tutulur?

izturk

#6
3. kütüphane dosyasını hal kütüphanesinden önce include edince hal fonksiyonları çalışmadı haliyle. .h dosyasının içerisinde yeniden hal kütüphanesini tanımlamam gerekiyor.


her kütüphanede bu şekilde yeniden hal kütüphanesini veya hangi kütüphaneleri kullanacaksam onları tanımlarsam problem yaşarmıyım.

Cemre.

https://www.picproje.org/index.php/topic,68498.0.html

Menü ile ilgili şu konuda çok güzel bir anlatım mevcut. Tavsiye ederim.

izturk

Öncelikle cevaplar için herkese teşekkür ederim.
Cemre. hocam menümü ben de benzer şekilde kurmuştum dizilerle. ama benim menümde seçmeli menüler alt menüler falan var. o yüzden biraz daha çeşitli oluyor.


benim burada asıl amacım c dilinde kütüphanelerin nasıl kullanılacağını tanımlamaların fonksiyonların nasıl oluşturulacağını öğrenmek işi biraz daha kuralına göre yapmaya çalışmak.


şimdiye kadar lazım olan kütüphane varsa ekledim kullandım. kütüphane bulamadıysam main içine fonksiyonlar yazarak işimi hallettim. c derslerine de bakıyorum ama bu konularla alakalı niyeyse hiç ders bulamıyorum.her anlatımda bi kenarından dokunmuş geçmiş. detaylı anlatım kaynak önerebilirseniz o kaynakları da incelerim.


herkese hayırlı geceler

foseydon

1. #ifndef = if not defined yani birseyin tanimli olup olmamasina gore #if bloğunun içine girer. bunu .h dosyalarında görmenin sebebi aynı kütüphanenin tekrar eklenmesini engellemektir. Zaten bu yapıya "inclusion guard" denir, yani ekleme koruması.

2. menü işini ben şu şekilde yapıyorum. menude yazacak şeyler için bir tablo var(array), her dil için ayrı tablo olacak haliyle. baska bır tabloda da struct tutuyorum. bu struct icerisinde her menuye ait fonksiyona giden bir pointer ve up/down/enter/escape vs. kac buton varsa onlarin tablonun hangi satirina gitmesi gerektigini gosteren bir index tutuyorum. bir menu fonksiyonu basilan tusu tespit ettigi zaman bu tabloya bakarak nereye gitmesi gerekgine karar veriyor ve oradaki fonksiyonu cagiriyor. fonksiyon icerisinde de menuye basilmasi gereken yaziyi bastiriyorum. boylece hersey birbirinden ayrilmis oluyor ve menu eklemek cikartmak oldukca kolay oluyor. dil destegi ekleme istersem bir tablo daha ekliyorum yeni dile ait, fonksiyon ekrana yazi basarken secili olan dile gore yazi tablosu secip onu bastiriyor. icinde ne oldugunu bilmiyor zaten.

3. bunun yerine bi tane .h dosyan olsun, butun kullanacagin kutuphaneleri buradan cagir. .c dosyalarinda sadece bu kutuphaneyi cagir is bitsin. boyle suna ekledim, buna eklemedim derdi ortadan kalkar.

Hittman

Öncelikle böyle bir konuyu açtığı için @yldzelektronik'e teşekkür ediyorum. Bir kaç haftadır bu konu üzerinde araştırma yapıyordum ve anlayamadığım bazı kısımlar oldu. Neyse ki bu konu açılmış ve o soruların bir kısmı kafamdan kalktı.  :D Site yetkililerinden ricam konunun üst kısma sabitlenmesi. Şimdi gelelim aklımda kalan diğer sorulara.
 Değerli üstadlar, şimdi bu .c ve .h dosyalarını kullanarak kütüphane nasıl oluşturulur temel düzeyde anladım. Fakat anlayamadığım bir kısım var ki bunu bir örnekle sormak istiyorum. Diyelim ki bir mikroişlemci programlayacağız ve uygulamamızda lcd kullanacağız. Bu yüzden bir tane lcd kütüphanesi yazmak istedik. Bu kütüphanenin içerisinde neler olacak? Mikroişlemciye ait fonksiyonlar mı? LCD ye ait fonksiyonlar mı? Ya da bunların karışımı mı? Ayrıca yazacağımız bu kütüphane LCD'yi kendi başına kontrol edebilir bir program mı yoksa tek başına bir anlamı olmayan bir program mı? Kısacası kafam biraz karışık  :)  Aydınlatırsanız çok sevinirim. Şimdi de teşekkür ediyorum cevaplayacak herkese.

sımışka

Tek başına kontrol edebilir mi kısmını tam anlayamadım fakat öncelikle senin .h dosyasında LCD ye ait segment/karakter tanımlamaları yapman gerekiyor. Ayrıca .c dosyasında oluşturacağın fonksiyonların prototiplerini tanımlayabilirsin.
.c de peki hangi fonksiyonları oluşturacaksın ? Örnek veriyorum ;
1. LCD_Display_Init --- Bu fonksiyon altında LCD pinlerinin ilgili entegrenin/mikroişlemcinin hangi pinlerine bağlıysa konfigürasyonu yapılır.
2. LCD_Display_Clear/Reset -- Bu fonksiyon altında tüm digitler/ segmentler temizleyebilirsin
3. LCD_Display_Set -- Bu fonksiyonla örneğin temizlendikten sonra ekrana yazdırmak istediğin örneğin 0xff karakterlerini yazdırabilirsin.
4. LCD_Display_SegmentWrite-- İlgili segmentleri set reset edebilirsin.
Bu liste uzar gider , temel fonksiyonların dışında birazda senin LCD yi nasıl kullanmak istediğine göre fonksiyon sayıları artıp azalabilir.
   

foseydon

Alıntı yapılan: Hittman - 02 Nisan 2018, 22:05:20Öncelikle böyle bir konuyu açtığı için @yldzelektronik'e teşekkür ediyorum. Bir kaç haftadır bu konu üzerinde araştırma yapıyordum ve anlayamadığım bazı kısımlar oldu. Neyse ki bu konu açılmış ve o soruların bir kısmı kafamdan kalktı.  :D Site yetkililerinden ricam konunun üst kısma sabitlenmesi. Şimdi gelelim aklımda kalan diğer sorulara.
 Değerli üstadlar, şimdi bu .c ve .h dosyalarını kullanarak kütüphane nasıl oluşturulur temel düzeyde anladım. Fakat anlayamadığım bir kısım var ki bunu bir örnekle sormak istiyorum. Diyelim ki bir mikroişlemci programlayacağız ve uygulamamızda lcd kullanacağız. Bu yüzden bir tane lcd kütüphanesi yazmak istedik. Bu kütüphanenin içerisinde neler olacak? Mikroişlemciye ait fonksiyonlar mı? LCD ye ait fonksiyonlar mı? Ya da bunların karışımı mı? Ayrıca yazacağımız bu kütüphane LCD'yi kendi başına kontrol edebilir bir program mı yoksa tek başına bir anlamı olmayan bir program mı? Kısacası kafam biraz karışık  :)  Aydınlatırsanız çok sevinirim. Şimdi de teşekkür ediyorum cevaplayacak herkese.

LCD kütüphanesi yazıyorsan, LCD'ye ait fonksiyonlar olacak. Fonksiyonları mikroişlemciden bağımsız yazacaksın. Kütüphanenin bir config dosyası olacak bu dosya içerisinde mikroişlemci ile LCD kütüphanesi arasındaki bağı kuracaksın. internette tonla yazılmış kütüphane var, bunları inceleyerek nasıl yapıldığını anlayabilirsin.

izturk

#13
Alıntı yapılan: Cemre. - 29 Mart 2018, 14:26:41extern int deger; diye kutuphane içerisinde tekrar tanımlayabilirsiniz. Ya da fonksiyona parametre olarak değerin adresini geçersiniz ve ona müdahale edersiniz. Ben olsam ikincisini tercih ederdim.

Yardımlarınız için teşekkürler.

Değişkeni kütüphane içinde extern olarak tanımlayarak veya fonksiyona adresini parametre olarak girerek hallettik. Ama şimdi başka bir sorum daha var.

cube mx spi init etmek için aşağıdaki gibi typdef tanımlamış

SPI_HandleTypeDef hspi3;

ben kütüphane içinde hal foksiyonlarında &hspi3 olarak kullanamıyorum.
kütüphane içinde
HAL_SPI_Transmit(&hspi3,cikis,4,100);
fonksiyonunu nasıl kullanacağım?

Düzeltme:
Sorumun cevabını buldum. Bunu da extern olarak yeniden tanımlayabiliyormuşuz.