ฟังก์ชันซ้อนใน C


97

เราสามารถมีฟังก์ชันซ้อนใน C ได้หรือไม่? การใช้ฟังก์ชันซ้อนกันคืออะไร? หากมีอยู่ใน C การนำไปใช้งานแตกต่างจากคอมไพเลอร์ถึงคอมไพเลอร์หรือไม่?


1
น่าจะซ้ำกับ: stackoverflow.com/questions/1348095/…
zoli2k

คำตอบ:


112

คุณไม่สามารถกำหนดฟังก์ชันภายในฟังก์ชันอื่นในมาตรฐาน C

คุณสามารถประกาศฟังก์ชันภายในฟังก์ชันได้ แต่ไม่ใช่ฟังก์ชันซ้อนกัน

GCC มีนามสกุลเป็นภาษาที่ช่วยให้การทำงานที่ซ้อนกัน ไม่เป็นมาตรฐานดังนั้นจึงขึ้นอยู่กับคอมไพเลอร์ทั้งหมด


36

ไม่ไม่มีอยู่ใน C

มีการใช้ในภาษาเช่น Pascal ด้วยเหตุผล (อย่างน้อย) สองประการ:

  1. อนุญาตให้มีการสลายตัวตามหน้าที่โดยไม่ทำให้เนมสเปซก่อมลพิษ คุณสามารถกำหนดฟังก์ชันที่เปิดเผยต่อสาธารณะเพียงฟังก์ชันเดียวที่ใช้ตรรกะที่ซับซ้อนบางอย่างโดยอาศัยฟังก์ชันซ้อนกันอย่างน้อยหนึ่งฟังก์ชันเพื่อแบ่งปัญหาออกเป็นชิ้นส่วนตรรกะที่เล็กลง
  2. ทำให้การส่งผ่านพารามิเตอร์ง่ายขึ้นในบางกรณี ฟังก์ชันที่ซ้อนกันสามารถเข้าถึงพารามิเตอร์ทั้งหมดและตัวแปรบางตัวหรือทั้งหมดในขอบเขตของฟังก์ชันด้านนอกดังนั้นฟังก์ชันด้านนอกจึงไม่จำเป็นต้องส่งกองสถานะภายในไปยังฟังก์ชันที่ซ้อนกันอย่างชัดเจน

21

ฟังก์ชั่นที่ซ้อนกันไม่ได้เป็นส่วนหนึ่งของANSI Cแต่พวกเขาเป็นส่วนหนึ่งของ Gnu C


จะมีความสำคัญอะไรหากพวกเขาเป็นส่วนหนึ่งของ Gnu C
Sachin Chourasiya

4
@Sachin ช่วยให้ทราบว่าเหตุใดโค้ด C ที่มีฟังก์ชันซ้อนกันจึงสามารถคอมไพล์ด้วย gcc ข้อมูลมีคุณค่าทางการศึกษา นอกจากนี้คำถามไม่ได้ระบุว่า จำกัด เฉพาะ C89, C99 หรือ GNU C
zoli2k

4
ภาษาอื่น ๆ ที่ GCC รองรับก็มี (ADA และ Pascal ที่ฉันรู้จัก) ดังนั้นจึงเป็นไปได้ว่าการเพิ่มการใช้งาน C เป็นเรื่องง่ายหรือเพิ่มลงใน C เพื่อเตรียมความพร้อมสำหรับภาษาที่รองรับซึ่ง ต้องการพวกเขา
nategoose

MATLAB ยังมีฟังก์ชันซ้อนกัน
mikeTronix

17

ไม่คุณไม่สามารถมีฟังก์ชันซ้อนกันCได้ สิ่งที่ใกล้เคียงที่สุดที่คุณสามารถมาได้คือการประกาศฟังก์ชันภายในนิยามของฟังก์ชันอื่น คำจำกัดความของฟังก์ชันนั้นจะต้องปรากฏอยู่นอกส่วนของฟังก์ชันอื่น ๆ

เช่น

void f(void)
{
    // Declare a function called g
    void g(void);

    // Call g
    g();
}

// Definition of g
void g(void)
{
}

6
ถ้าฟังก์ชัน g ถูกประกาศด้วยวิธีนี้ขอบเขตของมันจะเป็นอย่างไร?
Sachin Chourasiya

6
การประกาศจะถูกกำหนดขอบเขตเหมือนกับการประกาศอื่น ๆ ดังนั้นในกรณีนี้จนกว่าฟังก์ชันจะสิ้นสุด แน่นอนเมื่อคำจำกัดความของgสามารถมองเห็นได้ในภายหลังในไฟล์ที่การประกาศอยู่ในขอบเขตสำหรับหน่วยการแปลที่เหลือ นอกจากนี้คุณสามารถเรียกใช้ฟังก์ชันใน C โดยไม่ต้องมีการประกาศที่มองเห็นได้ในขอบเขตแม้ว่าจะไม่แนะนำก็ตาม
CB Bailey

5

ฉันพูดถึงสิ่งนี้เนื่องจากหลายคนที่เขียนโค้ดใน C ตอนนี้ใช้คอมไพเลอร์ C ++ (เช่น Visual C ++ และ Keil uVision) เพื่อทำสิ่งนี้ดังนั้นคุณอาจสามารถใช้ประโยชน์จากสิ่งนี้ได้ ...

แม้ว่าจะยังไม่ได้รับอนุญาตใน C แต่หากคุณใช้ C ++ คุณสามารถบรรลุผลเช่นเดียวกันกับฟังก์ชันแลมบ์ดาที่แนะนำใน C ++ 11:

void f()
{
    auto g = [] () { /* Some functionality */ }

    g();
}

4
คำถามเกี่ยวกับ C โดยเฉพาะไม่ใช่ C ++
Virgile

11
@Virgile - และคำถามยังระบุเป็นพิเศษว่า "อนุญาตให้ใช้ฟังก์ชันซ้อนในภาษาอื่นได้หรือไม่" คำตอบของจอนช่วยฉัน
www-0av-Com

3

ตามที่คนอื่นตอบมาตรฐาน C ไม่สนับสนุนฟังก์ชันซ้อนกัน

ฟังก์ชันที่ซ้อนกันใช้ในบางภาษาเพื่อรวมฟังก์ชันและตัวแปรหลายตัวไว้ในคอนเทนเนอร์ (ฟังก์ชันด้านนอก) เพื่อให้แต่ละฟังก์ชัน (ไม่รวมฟังก์ชันด้านนอก) และตัวแปรไม่สามารถมองเห็นได้จากภายนอก

ในCสามารถทำได้โดยใส่ฟังก์ชันดังกล่าวในไฟล์ต้นฉบับแยกต่างหาก กำหนดฟังก์ชั่นหลัก ๆ ทั่วโลกและทุกฟังก์ชั่นอื่น ๆ และตัวแปรเป็นแบบคงที่ ตอนนี้มีเพียงฟังก์ชันหลักเท่านั้นที่มองเห็นได้ภายนอกโมดูลนี้


หากมีการเรียกซ้ำouter-> nested-> outer-> nestedจะมีสองเฟรมที่แตกต่างกันint declared_in_outerคุณจึงไม่สามารถใส่declared_in_outerเป็นโกลบอลแบบคงที่ได้
Adrian Panasiuk

1

เพื่อตอบคำถามที่สองของคุณมีภาษาที่อนุญาตให้กำหนดฟังก์ชันซ้อนกันได้ (สามารถดูรายการได้ที่นี่: ฟังก์ชันที่ซ้อนกัน - ภาษารายการ - วิกิพีเดีย )

ใน JavaScript ซึ่งเป็นหนึ่งในภาษาที่มีชื่อเสียงที่สุดหนึ่งในฟังก์ชันซ้อนกัน (ซึ่งเรียกว่าการปิด) ได้แก่ :

  • เพื่อสร้างเมธอดคลาสในตัวสร้างอ็อบเจกต์
  • เพื่อให้บรรลุการทำงานของสมาชิกชั้นเรียนส่วนตัวพร้อมกับ setters และ getters
  • ไม่ก่อให้เกิดมลพิษต่อเนมสเปซทั่วโลก (แน่นอนว่าใช้ได้กับทุกภาษา)

เพื่อชื่อไม่กี่ ...


0

หรือคุณสามารถฉลาดเกี่ยวกับเรื่องนี้และใช้ตัวประมวลผลล่วงหน้าเพื่อประโยชน์ของคุณ ( source.c):

#ifndef FIRSTPASS
#include <stdio.h>

//here comes your "nested" definitions
#define FIRSTPASS
#include "source.c"
#undef FIRSTPASS

main(){
#else
    int global = 2;
    int func() {printf("%d\n", global);}
#endif
#ifndef FIRSTPASS
    func();}
#endif

-1

นี่ไม่ใช่ฟังก์ชันซ้อนใน C ใช่หรือไม่ (ฟังก์ชัน displayAccounts ())

ฉันรู้ว่าฉันสามารถกำหนดฟังก์ชั่นที่แตกต่างกันและส่งผ่านตัวแปรได้และสิ่งที่ไม่ได้ผลดีเพราะฉันต้องพิมพ์บัญชีหลาย ๆ ครั้ง

(snipet เอามาจากงานโรงเรียน) ...

//function 'main' that executes the program.
int main(void)
{
    int customerArray[3][3] = {{1, 1000, 600}, {2, 5000, 2500}, {3, 10000, 2000}};  //multidimensional customer data array.
    int x, y;      //counters for the multidimensional customer array.
    char inquiry;  //variable used to store input from user ('y' or 'n' response on whether or not a recession is present).

    //function 'displayAccounts' displays the current status of accounts when called.
    void displayAccounts(void)
    {
        puts("\t\tBank Of Despair\n\nCustomer List:\n--------------");
        puts("Account #    Credit Limit\t  Balance\n---------    ------------\t  -------");
        for(x = 0; x <= 2; x++)
        {
            for(y = 0; y <= 2; y++)
                printf("%9d\t", customerArray[x][y]);
            puts("\n");
        }
    }

    displayAccounts();  //prints accounts to console.
    printf("Is there currently a recession (y or n)? ");


//...

    return 0;
}

4
ไม่ใช่มาตรฐานทางกฎหมาย C หากใช้งานได้กับคอมไพเลอร์ของคุณนั่นเป็นเพราะคอมไพเลอร์ของคุณได้จัดเตรียมส่วนขยายให้กับภาษา C มาตรฐาน ในบางแง่คอมไพเลอร์ของคุณกำลังรวบรวมภาษาอื่นซึ่งก็คือพูดอย่างเคร่งครัดไม่ใช่ C.
Nate Eldredge

ขอบคุณสำหรับข้อมูลของคุณ ฉันได้เรียนรู้วิธีที่เหมาะสมในการประกาศกำหนดและใช้ฟังก์ชันต่างๆ นี่เป็นเรื่องน่าอายเล็กน้อยที่จะมองย้อนกลับไป>. <
MidnightCoder

1
@midnightCoder: คุณสามารถลบคำตอบของคุณได้ตลอดเวลา :)
chqrlie
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.