2009-09-09 3 views
22

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

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

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

+0

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

+0

@Suma: В C. не было бы функций-членов. –

ответ

23

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

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

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

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

#define f() f_should_not_be_called_by_anything_except_g 

Какой бы представить хорошее сообщение об ошибке, и авто-завершивших (например, Visual Studio) будет показано, что наконечник, когда пользователь е().

+1

Отметьте, что я сделал @John Milikin. – luizleroy

+0

Я знаю. На самом деле довольно легко исправить. –

+0

На самом деле, я поклонник ответа Джонатана Леффлера, но, по его словам, это не обобщаемо. Но я поддержал почти всех, кто сказал правильную (то есть «статическую» функцию). Вероятно, они искали. –

8

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

+1

Я не думаю, что это ожидаемый ответ. Это не мешает кому-либо использовать другие функции в одном источнике и cal f(). – luizleroy

+17

Любой, кто может редактировать функцию источника, может преодолеть * любую * схему для создания чего-то частного. – dmckee

33

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

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 
+1

Однако вы все равно можете вызвать f_real_name(). –

+1

Это правда, но не строго требование. Играйте с правилами, а не с намерениями. –

+3

Конечно, мы можем назвать 'f_real_name()'. Мы также можем вызывать 'printf()', 'malloc()' и многие другие полезные функции, но что это связано с вызовом 'f()'? –

10

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

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

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

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

2

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

Если функции 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(); 
} 

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

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

8

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