C coding design - function pointer?

24

Saya punya PIC18F46K22 dan memprogramnya dengan kompiler XC8. Pada akhirnya, saya akan memiliki sistem seperti komputer dengan stdindan stdout. Jadi di loop utama akan ada fungsi yang memeriksa apakah ada input baru. Jika ada input, fungsi akan dipanggil sesuai. Jadi misalnya ketika saya masukan A pada stdin, PIC akan menjalankan fungsi seperti function_Abukan function_Byang disebut ketika saya input B.

Ketika PIC selesai dengan fungsi, saya ingin input baru dikirim ke fungsi. Jadi ketika menekan A membuka pemancar RS232, sejak saat itu setiap input akan dikirim melalui RS232. Pada akhirnya proyek ini adalah editor teks yang berdiri sendiri. Jadi, ketika menekan A membuka sistem file, sejak saat itu Anda tidak lagi mengedit teks tetapi melihat melalui daftar file. Itu berarti bahwa menekan Atas dan Bawah berarti sesuatu yang berbeda dari pada lingkungan penyuntingan teks.

Saya telah melakukan banyak pemikiran tentang bagaimana memprogram ini dalam C. Saya memikirkan ini semalam dan ingin tahu apakah itu mungkin dan jika demikian, bagaimana. Yang ingin saya lakukan adalah:

  • The mainfungsi panggilan fungsi sepertifunction_A
  • function_Amengubah variabel global function_addrke penunjuk alamat fungsiin_function_A
  • Sejak saat itu, mainpanggil fungsi function_addrketika ada input baru.

Jadi yang saya butuhkan adalah mainfungsi yang memeriksa apakah function_addrnol. Jika ya, fungsi 'normal' harus dipanggil, misalnya function_A. Jika tidak, fungsi di function_addrharus dipanggil. Saya juga membutuhkan function_Ayang mengubah function_addrpointer ke in_function_A.

Catatan: ketika fungsi sistem file harus ditutup, is_function_Aseharusnya berubah function_addrmenjadi 0.

Jadi pada dasarnya pertanyaan saya adalah bagaimana saya bisa

  • Dapatkan alamat suatu fungsi (dan simpan dalam variabel)
  • Panggil fungsi di alamat yang ditentukan

sumber
6
Menyimpang dari topik. Milik stackoverflow.com.
user207421
Bagi saya, pendekatan mesin negara jauh lebih berisiko daripada berurusan dengan pointer fungsi. Byte input Anda diteruskan ke struktur mesin keadaan (bisa sesederhana switch-case) yang melompat ke berbagai bit kode sebagai fungsi dari variabel keadaan atau variabel. Juga, Anda tidak sepenuhnya jelas dari mana asal stdin Anda (bukan karena itu sangat berarti, tapi saya penasaran).
Adam Lawrence
9
@ EJP saya tidak setuju. Hanya karena ada tumpang tindih tidak berarti harus di satu situs atau yang lain. Ini mengajukan pertanyaan terkait dengan desain dan pemrograman sistem tertanam tingkat rendah, yang tampaknya pada topik di kedua tempat tersebut.
Kortuk
Mesin negara dapat didasarkan pada fungsi tipuan: panggilan ke fungsi transisi negara mengembalikan fungsi transisi negara baru.
Kaz
1
Mari kita bahas di sini .

Jawaban:

21

Sebuah fungsi

int f(int x){ .. }

Dapatkan alamat suatu fungsi (dan simpan dalam variabel)

int (*fp)(int) = f;

Panggil fungsi di alamat yang ditentukan

int x = (*fp)( 12 );
Wouter van Ooijen
sumber
3
+1, jelas di dunia C dan ASM, tetapi tidak begitu jelas bagi mereka yang memulai dengan bahasa OO.
Anindo Ghosh
4
Panggilan fp juga dapat ditulis sebagai 'int x = fp (12);' untuk meningkatkan keterbacaan.
Rev1.0
1
Saya harus mengakui, bekerja terutama di C # dan Java saat ini, saya kehilangan pointer fungsi lama yang baik dari C kadang-kadang. Mereka berbahaya ketika tidak dilakukan dengan benar, dan sebagian besar tugas dapat diselesaikan dengan cara lain, tetapi mereka benar-benar berguna beberapa kali ketika mereka benar-benar berguna.
CVn
@ MichaelKjörling: Benar sekali. Saya terus-menerus beralih antara pemrograman C dan C # yang tertanam (bahkan menerapkan kode serupa untuk komunikasi antara perangkat dan PC) dan sekuat C #, saya masih sangat menikmati C.
Rev1.0
2
fp(12)tidak meningkatkan keterbacaan (*fp)(12). Mereka memiliki keterbacaan yang berbeda. (*fp)(12)mengingatkan pembaca yang fpmerupakan penunjuk, dan juga menyerupai deklarasi fp. Dalam pikiran saya, gaya ini dikaitkan dengan sumber-sumber lama, seperti internal X11, dan K&R C. Salah satu alasan yang mungkin dikaitkan dengan K&R C adalah karena dalam ANSI C, dimungkinkan untuk mendeklarasikan fpmenggunakan sintaks fungsi, jika fpmerupakan parameter: int func(int fp(double)) {}. Dalam K&R C itu seharusnya int func(fp) int (*fp)(double); { ... }.
Kaz
17

Sementara jawaban Wouters benar sekali, ini mungkin lebih ramah bagi pemula dan contoh yang lebih baik tentang pertanyaan Anda.

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 */
}

Jika tidak jelas bahwa pointer fungsi sebenarnya memiliki alamat fungsi target yang ditetapkan, lebih baik untuk melakukan pemeriksaan NULL.

if (fp != NULL)
    fp(); /* with parameters, if applicable */
Rev1.0
sumber
8
+1 untuk cek nol, tetapi perlu dicatat bahwa kompiler mungkin tidak menjamin bahwa nilai pada alamat dalam RAM yang fpkebetulan menempati sebenarnya NULL pada awalnya. Saya akan melakukan int (*fp)(int) = NULL;sebagai deklarasi dan inisialisasi gabungan untuk memastikan - Anda tidak ingin melompat ke beberapa lokasi memori acak karena beberapa nilai konyol yang kebetulan ada di sana. Kemudian, tetapkan fpseperti pada Example()fungsi Anda .
CVn
1
Terima kasih atas komentarnya, saya menambahkan inisialisasi NULL.
Rev1.0
4
@ MichaelKjörling poin bagus, tetapi jika fpmerupakan "variabel global" (seperti kode int di atas), maka dijamin akan diinisialisasi ke NULL(tanpa harus melakukannya secara eksplisit).
Alok