C kodlama tasarımı - fonksiyon işaretçileri?


24

Bir PIC18F46K22’ye sahibim ve XC8 derleyicisiyle programladım. Sonunda, stdinve ile bir pc gibi bir sisteme sahip olacağım stdout. Böylece ana döngüde yeni giriş olup olmadığını kontrol eden bir fonksiyon olacaktır. Girdi varsa, buna göre bir işlev çağrılır. Mesela bir A girişi yaptığımda stdin, PIC bir B girdiğimde function_Abunun yerine function_Bçağrılan gibi bir işlevi çalıştıracaktır .

PIC işlevi ile yapıldığında, yeni girişin işleve gönderilmesini istiyorum. Böylece A düğmesine basıldığında RS232 vericisi açılır, o andan itibaren her giriş RS232 üzerinden gönderilir. Sonunda proje tek başına bir metin editörüdür. Böylece, A düğmesine basıldığında dosya sistemi açılır, o andan itibaren artık metin düzenlemesi yapmıyorsunuz ancak dosya listesine bakıyorsunuz. Bu, Yukarı ve Aşağı tuşlarına basmanın, metin düzenleme ortamından farklı bir şey anlamına gelir.

Bunu C dilinde nasıl programlayacağımı çok düşündüm. Dün gece bunu düşündüm ve mümkün olup olmadığını ve eğer öyleyse nasıl olduğunu bilmek istiyorum. Yapmak istediğim şey:

  • mainFonksiyon gibi bir işlevi çağırırfunction_A
  • function_Aglobal değişkeni function_addrfonksiyonun adres işaretçisine değiştiririn_function_A
  • O andan itibaren, yeni giriş olduğunda mainişlevi çağırır function_addr.

Yani ihtiyacım mainolan function_addrşey sıfır olup olmadığını kontrol eden bir fonksiyon . Eğer öyleyse, 'normal' bir işlev çağrılmalıdır function_A. Değilse, işlevinin function_addrçağrılması gerekir. Ayrıca bir ihtiyaç function_Adeğiştirir function_addriçin bir işaretçi in_function_A.

Not: dosya sistemi işlevi kapatıldığında, is_function_Asadece function_addr0 olarak değiştirilmelidir .

Yani temelde sorum şu: nasıl yapabilirim

  • Bir işlevin adresini al (ve değişkende sakla)
  • Belirtilen adreste bir işlev çağırın

6
Konu dışı. Stackoverflow.com 'a aittir.
user207421

Bana göre, bir devlet makinesi yaklaşımı, işlev göstericileri ile uğraşmaktan çok daha az riskli. Giriş baytınız, durum değişkeninin veya değişkenlerin bir fonksiyonu olarak çeşitli kod bitlerine atlayan bir durum makinesi yapısına (anahtarlama kutusu kadar basit olabilir) geçirilir. Ayrıca, stdininizin nereden geldiği konusunda tam olarak net değilsiniz (bu gerçekten önemli değil, ama merak ediyorum).
Adam Lawrence

9
@EJP Ben katılmıyorum. Sırf çakışma olduğu için, bir sitede veya diğerinde olması gerektiği anlamına gelmez. Her iki yerde de görünen düşük seviyeli gömülü sistemlerin tasarımı ve programlanması ile ilgili sorular soruyor.
Kortuk

Durum makineleri, fonksiyon indirmesine dayanabilir: durum geçiş fonksiyonuna yapılan çağrı, yeni bir durum geçiş fonksiyonuna döner.
Kaz

1
Burada bu tartışmayı yapalım .

Yanıtlar:


21

Bir işlev

int f(int x){ .. }

Bir işlevin adresini al (ve değişkende sakla)

int (*fp)(int) = f;

Belirtilen adreste bir işlev çağırın

int x = (*fp)( 12 );

3
+1, C ve ASM dünyasında belirgin, ancak OO dilleriyle başlayanlar için çok açık değil.
Anindo Ghosh

4
Fp çağrısı 'int x = fp (12);' olarak da yazılabilir. okunabilirliği artırmak için.
Rev1.0

1
İtiraf etmeliyim ki, şu anda esas olarak C # ve Java'da çalışıyorum, bazen C'deki eski güzel işaretçilerden özlüyorum. Tam olarak doğru yapılmazlarsa tehlikelidirler ve çoğu görev başka yollarla da yapılabilir, ancak çok işe yarayacakları zamanlar yararlı olur.
CV

@ MichaelKjörling: Çok doğru. Sürekli olarak gömülü C ve C # programlaması arasında geçiş yapıyorum (cihaz ve PC arasında iletişim için benzer bir kod bile uygulayabiliyorum) ve C # kadar güçlü olmasına rağmen hala C'den çok keyif alıyorum.
Rev1.0

2
fp(12)üzerinde okunabilirliği artırmaz (*fp)(12). Farklı okunabilirliğe sahiptirler. bir gösterici (*fp)(12)olan okuyucuyu hatırlatır fpve aynı zamanda bildirgesine benzer fp. Aklımda, bu tarz, X11 içindekiler ve K&R C gibi eski kaynaklarla ilişkilidir. K&R C ile ilişkilendirilebilecek olası bir neden, ANSI C'de fp, eğer fpbir parametre ise , fonksiyon sözdizimini kullanarak bildirmek mümkündür : int func(int fp(double)) {}. K & R'de bu olurdu int func(fp) int (*fp)(double); { ... }.
Kaz

17

Wouters'ın cevabı kesinlikle doğru olsa da , bu belki daha yeni başlayanlar için uygun ve sorunuzla ilgili daha iyi bir örnek.

int (*fp)(int) = NULL;

int FunctionA(int x){ 
    return x + x;
}

int FunctionB(int x){ 
    return x * x;
}

void Example(void) {
    int x = 0;

    fp = FunctionA;
    x = fp(3);  /* after this, x == 6 */

    fp = FunctionB;
    x = fp(3);  /* after this, x == 9 */
}

İşlev göstergesinin gerçekte atanmış bir hedef işlev adresine sahip olduğu açık değilse, NULL kontrol yapmak akıllıca olacaktır.

if (fp != NULL)
    fp(); /* with parameters, if applicable */

8
Boş denetim için +1, ancak derleyicinin RAM'de bulunan adresteki adresin fpaslında başlangıçta NULL olduğunu garanti edemeyeceğini unutmayın . Ben yapacağını int (*fp)(int) = NULL;kombine beyanı ve emin olmak için başlatma olarak - sen çünkü sadece orada olmak oldu ki bazı şapşal değerin rastgele bellek konumuna atlamak istemiyorum. O zaman sadece fonksiyonundaki fpgibi atayın Example().
CV

1
Yorum için teşekkürler, NULL başlatma eklendi.
Rev1.0

4
@ MichaelKjörling iyi bir nokta, ancak eğer fpbir "global değişken" ise (yukarıdaki gibi), o zaman NULL(açıkça belirtmek zorunda kalmadan) başlatılması garanti edilir .
Ocak'ta Alok
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.