Альтернатива вложенным функциям в C?

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

Для моей конкретной проблемы у меня есть эта функция:

double findroot(double (*fp)(double), double start, double end);

Он находит корень функции f (x) одной переменной с указателем функции в качестве аргумента.

Я хочу передать функцию нескольких переменных, в которой все, кроме одной, фиксированы. Например, f (x, a, b, c), где a, b и c - все переданные константы, а x - единственная переменная, которая изменяется. Как мне найти f (0, a, b, c), сохранив при этом функцию findroot такой же, чтобы функция findroot была многоразовой и универсальной, а не специфичной для этого случая?

Спасибо.


person user1801359    schedule 26.11.2014    source источник
comment
Итак, ваш вопрос сводится к следующему: какова альтернатива, если все возможности (кроме чрезмерного использования глобальных переменных, что само по себе является злом) исключены заранее. Я правильно понял?   -  person Deduplicator    schedule 26.11.2014
comment
Я не согласен с вашим дизайном. Во всех функциях, которые я пишу на C, которые принимают обратные вызовы, я always также принимаю указатель void* и заставляю обратный вызов принимать этот указатель в качестве своего первого параметра. Это продвигает хорошие принципы разработки программного обеспечения, позволяя функциям быть реентерабельными; В частности, это позволяет избежать использования внеполосных данных, считываемых через глобальные объекты. Например: typedef double (*SINGLEVARFN)(void* ctx, double x); double findRoot(SINGLEVARFN fn, void* ctx, double start, double end);   -  person Iwillnotexist Idonotexist    schedule 26.11.2014
comment
Лямбда с захватом, но C ++ обслуживает ваш запрос.   -  person Alexander V    schedule 26.11.2014
comment
Итак, ответ - использовать глобальные переменные или один из трех упомянутых мною вариантов? А как насчет использования макроса? Я просто пытаюсь придумать стандартное решение этой проблемы.   -  person user1801359    schedule 26.11.2014
comment
@ user1801359 (должно быть) стандартное решение - всегда разрешать обратным вызовам принимать частный указатель, передавать как обратный вызов, так и частный указатель на функцию, которая использует обратный вызов, и вызывать обратный вызов с предоставленным частным указателем. Вы знакомы с pthread_create()? Это модель того, как это делается правильно.   -  person Iwillnotexist Idonotexist    schedule 26.11.2014
comment
Другой стандарт - выяснить, способен ли findroot на это с самого начала. Если его среда сбрасывается / повторно инициализируется с каждым набором корней, это может не иметь смысла.   -  person David C. Rankin    schedule 26.11.2014
comment
@IwillnotexistIdonotexist Спасибо. Я собирался попросить простой пример. Я не знаком с pthread_create (), но я изучу его.   -  person user1801359    schedule 26.11.2014
comment
@ user1801359 pthread_create() - это функция, которая порождает поток в Unix. Его аргументы - это указатели на объекты атрибутов pthread_t и pthread_attr_t, указатель на обратный вызов void* (*) (void*) и указатель аргумента void* для обратного вызова. Когда создается новый поток, он вызывает обратный вызов с аргументом void*, предоставленным pthread_create(). Обратный вызов спроектирован так, что он принимает именно этот аргумент, и, таким образом, порождение потока не требует какого-либо глобального состояния или вложенных функций.   -  person Iwillnotexist Idonotexist    schedule 26.11.2014
comment
@ user1801359 прокомментировал: А как насчет использования макроса? Я просто пытаюсь придумать стандартное решение этой проблемы. Ваша проблема, возможно, в том, что вы воспринимаете это как проблему. Использование макроса, безусловно, хуже, чем ваша предполагаемая проблема! Кажется, вы задаете вопрос о том, что, по вашему мнению, является решением какой-то другой проблемы, которая сама по себе не имеет четкого объяснения. Попробуйте задать вопрос об основной проблеме, а не о неразрешимом решении.   -  person Clifford    schedule 26.11.2014
comment
Я не уверен, как (нечетко сформулированная) проблема предлагает вложенные функции в качестве решения.   -  person Clifford    schedule 26.11.2014
comment
Комментарии, предлагающие использовать обратный вызов, который принимает единственный указатель void в качестве единственного аргумента, по-прежнему имеют недостатки. Они требуют, чтобы вы либо структурировали свои функции очень специфическим образом, либо использовали вложенные функции. Я думаю, что если бы можно было легко использовать один аргумент, это не было бы вопросом. Однако следует принять компромисс. Эти решения элегантны.   -  person rbong    schedule 26.11.2014


Ответы (1)


Если вам нужно найти f (x, a, b, c), где a, b и c инвариантны, то это предлагает новую более специализированную функцию f2 (x) = f (x, a, b, c). Например:

double f2( double x )
{    
    return f( x, 1.0, 2.0, 3.0 ) ;
}
person Clifford    schedule 26.11.2014