การออกแบบการเข้ารหัส C - ตัวชี้ฟังก์ชั่น?


24

ฉันมีPIC18F46K22และตั้งโปรแกรมด้วยคอมไพเลอร์ XC8 ในท้ายที่สุดผมจะมีระบบเช่นเครื่องคอมพิวเตอร์ด้วยและstdin stdoutดังนั้นในลูปหลักจะมีฟังก์ชันที่ตรวจสอบว่ามีอินพุตใหม่หรือไม่ หากมีการป้อนข้อมูลฟังก์ชั่นจะถูกเรียกตาม ตัวอย่างเช่นเมื่อฉันป้อน A บนstdinPIC จะเรียกใช้ฟังก์ชันเช่นfunction_Aแทนที่จะfunction_Bเรียกว่าเมื่อฉันป้อน a

เมื่อ PIC เสร็จสิ้นด้วยฟังก์ชั่นฉันต้องการให้อินพุตใหม่ถูกส่งไปยังฟังก์ชั่น ดังนั้นเมื่อกด A จะเปิดตัวส่งสัญญาณ RS232 จากช่วงเวลานั้นทุกอินพุตจะถูกส่งผ่าน RS232 ในที่สุดโครงการนี้เป็นโปรแกรมแก้ไขข้อความแบบสแตนด์อโลน ดังนั้นเมื่อกด A จะเป็นการเปิดระบบไฟล์จากช่วงเวลานั้นคุณจะไม่แก้ไขข้อความอีกต่อไป แต่ลองดูรายการไฟล์ต่างๆ นั่นหมายความว่าการกดขึ้นและลงหมายถึงสิ่งที่แตกต่างจากในสภาพแวดล้อมการแก้ไขข้อความ

ฉันได้คิดมากเกี่ยวกับวิธีการเขียนโปรแกรมใน C. ฉันคิดว่าเมื่อคืนนี้และอยากจะรู้ว่าเป็นไปได้หรือไม่และถ้าเป็นเช่นนั้น สิ่งที่ฉันต้องการจะทำคือ:

  • mainเรียกฟังก์ชันการทำงานเช่นfunction_A
  • function_Aเปลี่ยนตัวแปรโกลบอลfunction_addrเป็นตัวชี้แอดเดรสของฟังก์ชันin_function_A
  • จากช่วงเวลานั้นmainเรียกใช้ฟังก์ชันfunction_addrเมื่อมีอินพุตใหม่

สิ่งที่ฉันต้องการคือmainฟังก์ชั่นที่ตรวจสอบว่าfunction_addrเป็นศูนย์หรือไม่ ถ้ามันเป็นฟังก์ชั่น 'ปกติ' function_Aควรจะเรียกว่าเหมือน ถ้าไม่ใช่ฟังก์ชันที่function_addrควรจะถูกเรียก ฉันยังต้องfunction_Aซึ่งการเปลี่ยนแปลงที่จะชี้ไปยังfunction_addrin_function_A

หมายเหตุ: เมื่อควรปิดฟังก์ชั่นระบบแฟ้มis_function_Aควรเปลี่ยนfunction_addrเป็น 0

ดังนั้นโดยทั่วไปคำถามของฉันคือฉันจะทำอย่างไร

  • รับที่อยู่ของฟังก์ชั่น (และเก็บไว้ในตัวแปร)
  • เรียกใช้ฟังก์ชันตามที่อยู่ที่ระบุ

6
ปิดหัวข้อ เป็นของ stackoverflow.com
user207421

สำหรับฉันแล้วการใช้เครื่องรัฐนั้นมีความเสี่ยงน้อยกว่าการใช้ตัวชี้ฟังก์ชั่น ไบต์อินพุตของคุณถูกส่งผ่านไปยังโครงสร้างเครื่องรัฐ (อาจจะง่ายเหมือนสวิตช์กรณี) ซึ่งข้ามไปยังบิตของรหัสต่างๆเป็นฟังก์ชั่นของตัวแปรสถานะหรือตัวแปร นอกจากนี้คุณยังไม่ชัดเจนว่า stdin ของคุณมาจากไหน (ไม่ใช่ว่ามันสำคัญมาก แต่ฉันอยากรู้)
Adam Lawrence

9
@EJP ฉันไม่เห็นด้วย เพียงเพราะมีการทับซ้อนไม่ได้หมายความว่ามันจะต้องมีในเว็บไซต์หนึ่งหรืออื่น ๆ มันกำลังถามคำถามที่เกี่ยวข้องกับการออกแบบและการเขียนโปรแกรมของระบบฝังตัวระดับต่ำที่ดูเหมือนว่าในหัวข้อที่ทั้งสอง
Kortuk

เครื่องรัฐสามารถขึ้นอยู่กับฟังก์ชั่นทางอ้อม: การเรียกไปยังฟังก์ชั่นการเปลี่ยนสถานะส่งกลับฟังก์ชั่นการเปลี่ยนสถานะใหม่
Kaz

1
ช่วยให้มีการสนทนานี้ที่นี่

คำตอบ:


21

ฟังก์ชั่น

int f(int x){ .. }

รับที่อยู่ของฟังก์ชั่น (และเก็บไว้ในตัวแปร)

int (*fp)(int) = f;

เรียกใช้ฟังก์ชันตามที่อยู่ที่ระบุ

int x = (*fp)( 12 );

3
+1 ชัดเจนในโลก C และ ASM แต่ไม่ชัดเจนสำหรับผู้ที่เริ่มต้นด้วยภาษา OO
Anindo Ghosh

4
การเรียก fp สามารถเขียนเป็น 'int x = fp (12);' เพื่อเพิ่มความสามารถในการอ่าน
Rev1.0

1
ฉันต้องยอมรับการทำงานส่วนใหญ่ใน C # และ Java ในปัจจุบันฉันคิดถึงตัวชี้ฟังก์ชั่นเก่าที่ดีจาก C ในบางครั้ง พวกมันอันตรายเมื่อทำไม่ถูกต้องและงานส่วนใหญ่สามารถทำได้ในรูปแบบอื่น แต่พวกเขามั่นใจว่ามีประโยชน์ในช่วงเวลาที่พวกเขาเข้ามามีประโยชน์จริง ๆ
CVN

@ MichaelKjörling: จริงจัง ฉันสลับไปมาอย่างต่อเนื่องระหว่างการเขียนโปรแกรม C และ C # แบบฝังตัว (แม้จะใช้รหัสที่คล้ายกันสำหรับการสื่อสารระหว่างอุปกรณ์และพีซี) และยิ่งใหญ่เท่า C # อาจจะฉันยังสนุกกับ C มาก
Rev1.0

2
fp(12)(*fp)(12)ไม่ได้เพิ่มการอ่านมากกว่า พวกเขามีความสามารถในการอ่านที่แตกต่างกัน (*fp)(12)เตือนผู้อ่านที่เป็นตัวชี้และยังมีลักษณะคล้ายกับการประกาศของfp fpในใจของฉันสไตล์นี้เชื่อมโยงกับแหล่งข้อมูลเก่าเช่น X11 internals และ K&R C เหตุผลหนึ่งที่เป็นไปได้ที่อาจเกี่ยวข้องกับ K&R C นั้นเป็นเพราะใน ANSI C เป็นไปได้ที่จะประกาศfpโดยใช้ฟังก์ชันไวยากรณ์ถ้าfpเป็นพารามิเตอร์: int func(int fp(double)) {}. ใน K & R C int func(fp) int (*fp)(double); { ... }ที่จะได้รับ
Kaz

17

ในขณะที่คำตอบของ Woutersนั้นถูกต้องอย่างแน่นอนผู้เริ่มต้นอาจเป็นมิตรมากกว่าและเป็นตัวอย่างที่ดีกว่าเกี่ยวกับคำถามของคุณ

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

หากไม่ชัดเจนว่าตัวชี้ฟังก์ชั่นจริงมีที่อยู่ฟังก์ชันเป้าหมายที่กำหนดไว้แล้วก็ควรทำการตรวจสอบ NULL

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

8
+1 สำหรับการตรวจสอบค่า null แต่โปรดทราบว่าคอมไพเลอร์อาจไม่รับประกันว่าค่าที่อยู่ใน RAM ที่fpเกิดขึ้นจริง ๆ แล้วจะเป็น NULL ในตอนแรก ฉันจะint (*fp)(int) = NULL;ประกาศรวมและการเริ่มต้นเพื่อให้แน่ใจ - คุณไม่ต้องการข้ามไปยังตำแหน่งหน่วยความจำแบบสุ่มเพราะมีค่าที่โง่ ๆ ที่เพิ่งเกิดขึ้นที่นั่น จากนั้นเพียงกำหนดfpเหมือนในExample()ฟังก์ชั่นของคุณ
CVN

1
ขอบคุณสำหรับความคิดเห็นที่ฉันเพิ่มการเริ่มต้นเป็นโมฆะ
Rev1.0

4
@ MichaelKjörlingจุดที่ดี แต่ถ้าfpเป็น "ตัวแปรทั่วโลก" (เป็น int เขารหัสด้านบน) ก็จะรับประกันว่าจะเริ่มต้นได้NULL(โดยไม่ต้องทำอย่างชัดเจน)
Alok
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.