it-swarm.com.ru

Как реализовать "частную/ограниченную" функцию в C?

Во время интервью на C мне был задан очень интересный вопрос: как реализовать функцию f() таким образом, чтобы ее можно было вызывать только из определенной функции g(). Если функция, отличная от g(), попытается вызвать f(), это приведет к ошибке компилятора.

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

У кого-нибудь есть идеи?

27
luizleroy

Вот один из способов:

int f_real_name(void)
{
    ...
}

#define f f_real_name
int g(void)
{
    // call f()
}
#undef f

// calling f() now won't work

Другой способ, если вы можете гарантировать, что f() и g() являются единственными функциями в файле, это объявить f() как static.

Правка: еще один макрос трюк, чтобы вызвать ошибки компилятора:

static int f(void) // static works for other files
{
    ...
}

int g(void)
{
    // call f()
}
#define f call function

// f() certainly produces compiler errors here
37
Chris Lutz

Поместите g() и f() в один и тот же модуль и объявите f() как статический. Ключевое слово static делает f() доступным только для функций в том же модуле или в исходном файле.

Вы также можете упомянуть, что в модуле нельзя использовать другие методы с f() и g (), иначе они могут вызывать f ().

PS - Я действительно думаю, что ответ Криса Латца на самом деле лучший. В нем упоминается этот подход, но также и умное переименование макросов, которое работает с меньшим количеством условий среды (не требует файл модуля специально для этих двух функций).

Также обратите внимание, что с макросом вы можете сделать следующее:

#define f() f_should_not_be_called_by_anything_except_g

Что будет отображать сообщение об ошибке Nice, а автозаполнение (например, Visual Studio) будет показывать этот совет, когда пользователь вводит f ().

26
Walt W

Вы можете создавать закрытые для модуля функции с ключевым словом static:

static void func(void)
{
    // ...
}

Тогда func() может быть вызван только другими функциями, определенными в том же файле (технически, тот же модуль перевода : другие функции, определения которых включены в директиву #include, все еще могут обращаться к нему). Говорят, что func имеет внутреннюю связь . Все другие функции (то есть без ключевого слова static), как говорят, имеют external linkage.

Кроме того, нет, невозможно сделать функции недоступными. Вы можете использовать макросы для изменения имени функции, но другой код всегда может получить к ней доступ с соответствующим именем.

10
Adam Rosenfield

Опция для GCC - использовать вложенные функции . Хотя это не стандартный C, он работает довольно хорошо.

8
outis

Поместите f() и g() в один и тот же исходный файл, объявив f() статическим.

8
John Millikin

Это возможно только по совпадению.

Если функции f() и g() находятся в одном и том же исходном файле, и в этом файле нет других функций, и если g() никогда не возвращает указатель функции на f() для любого из его вызывающих абонентов, тогда выполнение f() статического сделает эту работу.

Если другие функции должны появиться в том же исходном файле, поместите f() внизу файла как статическую функцию и определите g() только сразу после того, как он достигнет более или менее того же самого эффект - хотя, если вы не сказали компилятору генерировать ошибки в «пропущенных декларациях», другие функции могли бы вызывать его с предупреждениями.

#include <stdio.h>

extern void g(void);    /* in a header */

/* Other functions that may not call f() go here */

static void f(void)
{
    puts("X");
}

void g(void)
{
    f();
}

Очевидно, что этот метод нельзя надежно распространить на другую пару функций в том же файле - x() и y() - такую, что x() и только x() может вызывать y(), тогда как g() и только g() могут вызывать f() одновременно.

Однако обычно вы полагаетесь на дисциплину программистов и просто делаете f() статичным в исходном файле вместе с комментарием, который может вызывать только g(), а затем дисциплинируете любого, кто изменяет код, так что функция, отличная от g(), вызывает f ().

2
Jonathan Leffler

Вы можете сделать это

//some code ...
//You Can't call f() in here - compile time error
//some code ...
void f()
{
    //implement f() in here
}
void g()
{
    //You can only call f() in here - no error
}
#define f() Gimme some ERRORS!!!
//some code ...
//You Can't call f() in here - compile time error
//some code ...
0
Tomer Wolberg