Объявление прототипов функций локально в других функциях в C

#c

Вопрос:

В чем смысл создания вложенной функции? Иногда это происходит в книге Kamp;R «Язык программирования C», например, на странице 110 они объявляют функцию подкачки в qsort:

 void qsort(char *v[], int left, int right)
{
   int i, last;
   void swap(char *v[], int i, int j);
   etc.
 

Это только вопрос стиля или за этим стоит более важный аспект?

Комментарии:

1. пространство имен и действительность

2. Мои 5 центов — я никогда не видел, чтобы кто-то делал это в каком-либо производственном коде за весь мой многолетний опыт работы на языке Си.

3. Многие Kamp;R следуют духу «давайте делать глупости просто потому, что мы можем». Я бы не рекомендовал использовать эту книгу для обучения.

4. Якобы это делается для того, чтобы ограничить видимость swap того, чтобы qsort . На самом деле это довольно бесполезная практика. Жизнь становится просто проще, если вы определяете вызываемые функции перед их вызывающими (если обе они находятся в одном и том же исходном файле) — таким образом, вам вообще не нужно поддерживать отдельное объявление. Я этого не делаю, и за 30 лет я не видел, чтобы кто-то делал это за пределами учебника. Это просто действительно не имеет смысла в реальном коде.

5. «Давайте делать глупости, потому что мы можем» — это, пожалуй, наименее точная характеристика Kamp;R, которую я когда-либо видел. Части этой книги датированы, это правда, но в ней также содержится огромное количество мудрой, преуменьшенной мудрости. (Но здесь, конечно, не место для дебатов по этому поводу, и если кто-то пожелает высказать противоположное мнение, я оставлю за вами последнее слово; я не буду публиковать дальнейшие сообщения в этой теме.)

Ответ №1:

Это ограничивает видимость объявленной функции для этой функции.

Например, если у нас есть файл hw.c , содержащий

 #include <stdio.h>

void printHelloWorld()
{
    printf("Hello worldn");
}
 

и файл main.c , который содержит

 void func()
{
    // printHelloWorld(); // Incorrect, function is not visible here.
}

int main()
{
    void printHelloWorld();
    printHelloWorld();

    func();
}
 

тогда функция printHelloWorld видна только main функции для этого файла.

Аналогичное, хотя и менее полезное приложение-это когда две функции находятся в одном файле. Допустим main , сначала определяется (как указано выше) и printHelloWorld определяется под ним. Затем printHelloWorld будет видно из его определения вниз, за исключением того, что оно также будет видно внутри main .

Тем не менее, этот метод объявления функций встречается редко, и я бы не назвал его идиоматическим C.

Комментарии:

1. @Студент, я уверен, что они могли бы, но по какой-то причине решили не делать этого здесь. Чтобы быть справедливым к Kamp;R, первое издание вышло в 1978 году, а второе-в 1988 году. Это было до того, как многие (публично видимые) C был написан, так что то, что сейчас не считается идиоматичным, возможно, тогда было в порядке вещей.

2. @Студент: Это такой же артефакт написания кода для учебника, как и все остальное — на печатной странице не так много недвижимости, поэтому некоторые примеры немного хитры во имя экономии места. Это также может быть функцией желания донести конкретную концепцию, не обязательно самый идиоматичный способ ее написания. И, наконец, то, что составляет «идиоматический» код C, сильно изменилось с тех пор, как был написан Kamp;R.

3. Я иногда объявлял внешние функции локально. Я больше так не делаю. Я не думаю, что в любом случае это имеет большое значение. И да, консенсус по различным аспектам «идиоматического кода на языке Си» за эти годы довольно сильно изменился.

4. @Студент Большинство примеров из книги были написаны в середине 1970-х годов до того, как были изобретены идиоматический язык Си и хорошие методы программирования в целом. Поэтому они не могли написать идиоматический C, потому что его еще предстояло изобрести. В 1980-х годах само Kamp;R считалось идиоматичным, поскольку буквально не с чем было сравнивать. То, что позже стало идиоматичным, установилось только после стандартизации в 1989 году, после того как большая часть кода в Kamp;R устарела. А затем, со 2-й редакцией C в 1999 году, то, что было идиоматическим, изменилось во многих местах.