Практическое применение или значение объема прототипа функции - PullRequest
0 голосов
/ 02 мая 2020

Прежде всего: при поиске ответов мне разрешается [отмечать] области для поиска. Этот интерфейс публикации также должен поддерживать это.

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

function(int index, float array[index]);
//function prototype with names

против

function(int, float);
//function prototype(without identifiers)...

Определение функции всегда включает возвращаемый аргумент, имя функции и аргументы функции, включая тип и имена. кажется, что наличие области действия прототипа было бы излишним, так как аргументы в любом случае повторно объявляются с именами:

Прототип: return_type return_name (arguments_type, ...);

Объявление функции:

return_type return_name(argument_type argument_name, ...){
    compound_statement_function_block;
}

Единственное значение, которое я вижу, это то, что оно резервирует имя функции в пространстве имен области файла, что означает, что имя функции можно использовать в прототипе:

int func(int func);    //Proto type declaration. Compiler allows this
                       //but throws warning about func() redeclaration
                       //but nothing about the arguments.

int function(int function){
    int function;
}

Я изначально думал, что область видимости не зависит от имен, что означает, что file_scope_variable_name отличается от file_scope_function_name. Они контекстуально и значительно отличаются друг от друга, чтобы быть такими, и я подумал, что это то, к чему призывает стандарт, однако используемый мной компилятор g cc не допустит этого. Тем не менее, он разрешает main повторно объявляться как тег в пространстве имен struct / union в любой области видимости, поскольку они являются блочным элементом, подобным функции:

int func(int func){
    typedef struct {
        int func;
    };                 //Cannot use func as a variable name at function scope 
                       //since it is an argument even though 
                       //this is within a different namespace
    typedef union func{
        int (*func)(int func); //Shows func() name and arg. names
                               //are different namespaces.
        union u{
            int func;
            //...
        }
    } ;
}

int main(int main){
    typedef struct main {
        int main;
    };
}

Кажется, что main является зарезервированным ключевым словом в уровень файла для имен переменных и функций, но не для имен структур / тегов. Он принимает это на уровне файлов:

struct main {
    int main;
    //...
} not_main;

Нет смысла, почему пространства имен как таковые для прототипа. Если бы у него не было практической пользы, это не было бы различием.

1 Ответ

0 голосов
/ 02 мая 2020

Предварительный

Вы смешиваете по крайней мере три различных понятия, которые применяются к C идентификаторам: scope , пространство имен и linkage :

  • Область действия - это область текста программы, в которой данная связь между идентификатором и конкретным объектом программы является видимой и может использоваться.

  • Пространство имен описывает тот факт, что C позволяет использовать один и тот же идентификатор в одной и той же области видимости для идентификации объектов в определенных контекстно различимых категориях: метки, теги, структура и члены объединения, и все остальное.

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

Область применения и связь по существу отдельные соображения. Объявления области видимости обычных идентификаторов могут иметь как внешнюю, так и внутреннюю связь. Декларации области видимости обычных идентификаторов могут иметь внешнюю связь или не иметь связи. Все объявления идентификаторов в другом пространстве имен не имеют связи.


Вопрос

... немного широк, но я постараюсь затронуть основные моменты.

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

Наличие области действия прототипа функции позволяет включать имена параметров в прототипы функций. Если в прототипе не предусмотрена область для идентификаторов параметров функции, то единственной областью, к которой они могут принадлежать, будет область файла, и это будет означать, что каждое имя параметра должно отличаться от любого другого в файле, и это каждой переменной области файла. Это также подразумевает, что параметры функции могут быть доступны извне функции. И, конечно же, возникнет проблема с несколькими объявлениями функций, которые предоставляют разные имена параметров. Какой беспорядок!

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

  • упрощает создание отдельных прототипов (просто возьмите один из определения функции и удалите тело функции)
  • делает прототипы функций гораздо более значимыми для человек-читатель, особенно с хорошим выбором имен параметров
  • , он позволяет компиляторам предоставлять более полезные диагностические c сообщения

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

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

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

Единственное значение, которое я вижу, это то, что оно резервирует имя функции в значении пространства имен области файла. имя функции может использоваться в прототипе

Это имеет такой эффект, хотя я редко вижу идентификатор функции, используемый в качестве имени одного из ее собственных параметров. Но более распространенным является то, что имя функции области действия файла появляется также как имя параметра какой-либо другой функции. Или, что имя переменной области файла появляется как имя параметра функции.

Я изначально думал, что область не зависит от имен, означая, что file_scope_variable_name отличается от file_scope_function_name.

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

[мой компилятор], однако, позволит объявляется как тег в пространстве имен struct / union в любой области видимости, поскольку они являются блочным элементом, таким как функция

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

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

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

...