2016-09-25 5 views
1

Я знаю, что C не поддерживает вложенные функции, и это только расширение gcc. Но даже в этом случае это поведение странно.C-вызов вызова вложенной функции

Кажется, что вложенные функции можно вызвать только один раз; второй вызов вызывает SIGSEV, а иногда и SIGILL. Мне нужны вложенные функции для таких структур, как stack. В стеке я мог бы определить такие функции, как pop, push и т. Д., Которые я буду назначать с помощью вложенных функций, которые вызовут нормальные функции со ссылкой, которые я получу. Эта функция похожа на конструктор или инициализатор. Но этого кода достаточно, чтобы смоделировать мою проблему.

При генерации функции присваивает innerFunction в struct, второй вызов вызывает ошибку. Если назначение - проверить функцию, второй вызов - это нормально.

В чем проблема, пожалуйста? В документации gcc говорится, что до тех пор, пока у вас есть внутренний адрес функции, вы можете получить доступ к этой функции, а вложенная функция имеет доступ ко всем указанным выше переменным.

typedef struct A A; 

struct A { 
    void (*foo)(); 
}; 

void test() { 
    printf("test\n"); 
} 

void generate(A* a) { 

    void innerTest(){ 
     test(); 
    } 

    a->foo = &innerTest; 
} 


int main() { 

    A a; 
    generate(&a); 

    a.foo(); 
    a.foo(); 
}; 
+2

В чем проблема? Я правильно скомпилировал и выполнил ваш код. – acornagl

+0

Я считаю, что вложенные функции не соответствуют друг другу. Даже если он может работать –

+3

В документации [https://gcc.gnu.org/onlinedocs/gcc/Nested-Functions.html#Nested-Functions] фактически говорится: «Если вы пытаетесь вызвать вложенную функцию по ее адресу после того, как функция сложения выходит, все ад разрывается. * « – melpomene

ответ

0

Не позволяйте указателям выполнять внутренние функции, чтобы избежать рамки стека, на которой они были созданы. Это дает неопределенное поведение.

Созданный код помещает батут в стек. С конкретной конструкцией, которую вы создали, батут был перезаписан первым вызовом функции, поэтому он не смог выполнить второй вызов функции.

Меня лично раздражает, что он вызывает это поведение без закрытия, чтобы заботиться о нем, но это то, что он делает. Ой, подождите, я понял. ваш пример работает, потому что, спаривая это, вы случайно уменьшили его до рабочего кода (см. комментарий acorngal). Ваш реальный код обращается к указателю на структуру, помеченную a и т. Д., Заставляет закрытие и, следовательно, батут. Вы не можете сделать этот трюк в C; при выполнении программирования OO вы должны передать эквивалент указателю this.

+0

Батут создается, когда принимается адрес вложенной функции. Я до сих пор не понимаю, почему батут переписан. Не могли бы вы объяснить причину и решение не иметь этого поведения? –

+0

Батут освобождается, как только вы возвращаетесь от функции. Первый вызов работал, потому что освобожденная память еще не была перезаписана. Вы пытаетесь написать конструкцию, требующую сбора мусора, в C, которая не является сборкой мусора. Решение заключается в редизайне, чтобы не зависеть от сборщика мусора. – Joshua

Смежные вопросы