Подтвердить что ты не робот

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

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

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

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

4b9b3361

Ответ 1

Здесь один из способов:

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.

EDIT: другой макрокоманд, вызывающий ошибки компилятора:

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

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

// f() certainly produces compiler errors here

Ответ 2

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

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

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

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

#define f() f_should_not_be_called_by_anything_except_g

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

Ответ 3

Вы можете сделать модульные частные функции с помощью ключевого слова static:

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

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

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

Ответ 4

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

Ответ 5

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

Ответ 6

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

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

Если в том же исходном файле должны появляться другие функции, помещая 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().