Имеют ли объявления параметров в объявлениях функций область действия прототипа функции? - PullRequest
0 голосов
/ 16 мая 2018

В п. 6.2.1 (2) Стандарта ISO C11 (черновик) прототип функции определяется как (выделено мной)

Прототип функции - это объявление функции , которая объявляет типы ее параметров.

Так декларация, такая как void (*f)( struct s { int c; } ); не является объявлением функции (это объявление указателя на функцию) и, следовательно, тег s имеет область видимости файла или блока (в зависимости от того, где это объявление появляется). Тогда может показаться, что следующий блок перевода void (*f)( struct s { int c; } ); struct s a[42]; должно быть полностью соответствующим (оставляя в стороне любые вопросы юзабилити). Тем не менее, gcc создает диагностический «массив неполных типов» (и предупреждение о том, что s имеет область действия, ограниченную списком параметров), сигнализируя о том, что s имеет область действия прототипа функции, даже если формально нет объявления функции.

Было ли намерение Стандарта утверждать, что список параметров в каждой функции , декларатор определяет свою собственную область видимости (как, по-видимому, gcc и любой другой компилятор интерпретируют это)? Это намерение выражено более формально где-нибудь в стандарте? Любой отчет о дефектах, который еще не вошел в стандарт?

Конечно, это вопрос адвоката, и я ценю, что такие «подлые» объявления тегов - плохой стиль. Помимо того, что s является неполным типом в объявлении a выше, проблемы с областями видимости также делают невозможным определение функции с прототипом *f. Наконец, чтобы избежать использования самого f, можно поместить всю декларацию f в sizeof, как в int b[sizeof(void (*)( struct s { int c; } ))];

Ответы [ 4 ]

0 голосов
/ 16 мая 2018

На самом деле параметры или аргументы - это 1 часть Прототипа функции.Прототип функции состоит из 3 основных компонентов: 1. Тип функции 2. Имя функции 3. Аргументы или параметры

0 голосов
/ 16 мая 2018

Давайте сначала обратимся к аналогии

struct foo* x;

объявляет указатель на struct foo, но все же struct foo в этом объявлении является (прямым) объявлением типа struct.

Теперь

int (*f)(int);

- объявление указателя на функцию. Указатель является указателем на базовый тип int ()(int), который имеет тип функции с прототипом.

Тогда

int (*g)(struct toto { int a; });

снова является объявлением указателя функции. Указатель является указателем на базовый тип int ()(struct toto { int a; }), который имеет тип функции с прототипом.

Или, резюмируя, объявление указателя на что-то также объявляет то, на что указывает указатель.

0 голосов
/ 16 мая 2018

Так что объявление типа void (*f)( struct s { int c; } ); не является объявлением функции (это объявление указателя на функцию) ...

Я не согласен.

Пункт 6.7.6 Деклараторы содержат:

Синтаксис

  • Декларатор:

    Указатель opt прямой декларатор

  • прямой декларатор:идентификатор(декларатор)прямой декларатор [список спецификаторов типов опт выражение-присваивания]прямой декларатор [статический список-спецификатор типов opt выражение-назначение]прямой-декларатор [статический список-присваивания-список-спецификаторов типов]прямой декларатор [список-спецификатор типа опт *]прямой декларатор (параметр-тип-список)прямой декларатор (идентификатор-список opt )
  • указатель:* type-qualifier-listoptуказатель * type-qualifier-list opt ...

Мое понимание этого предложения состоит в том, что void (*f)( struct s { int c; } ); действительно является объявлением указателя, но это объявление указателя включает определение прототипа функции в его прямой декларатор часть.Таким образом, применяется вся семантика определения прототипа функции.

Таким образом, область действия struct s составляет объявление прототипа функции части прямого объявления объявления указателя.И в п. 4 раздела 6.2.1 говорится:

Если декларатор или спецификатор типа, который объявляет идентификатор, появляется в списке объявлений параметров в прототипе функции (не является частью определения функции), идентификаторимеет область действия прототипа функции, которая заканчивается в конце объявления функции.

Мы именно в этом случае (без определения), поэтому область объявления struct s заканчивается в концестрока.

Таким образом, gcc совершенно прав, когда выдает диагностический «массив неполных типов» (и предупреждение о том, что s имеет область видимости, ограниченную списком параметров), сигнализируя, что s имеет область действия прототипа функции, даже еслиформально нет объявления функции.

0 голосов
/ 16 мая 2018

В ходе длительного обсуждения в комментариях выяснилось, что этот вопрос действительно о точном значении комментария в скобках в §6.2.1 / 2: «Прототип функции являетсяобъявление функции, которая объявляет типы ее параметров. "

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

  1. §6.2.7 / 3 Совместимый тип и составной тип:

    Если только один тип является типом функции со списком типов параметров (прототип функции), составной тип является прототипом функции со списком типов параметров.

    В этом случае первое использование «прототипа функции», очевидно, не ограничивается объявлением функции, посколькуговорит "тип функции" - это может быть тип, неявно созданный во время разрешения объявления указателя на функцию - и второе использование "прототипа функции" может вообще не иметь синтаксического представления, поскольку это типсозданный в ходе алгоритма составного типа

  2. §6.5.2.2 Вызовы функций

    Здесь параграф 2 применяется к функциям с «типом, включающим прототип»в то время как в параграфе 6 функции сравниваются с «типом, который не включает в себя прототип», с функциями с «типом, который включает в себя прототип».Такое использование несовместимо с приведенным выше «определением» «прототипа функции», поскольку это определение относится к типу функции в целом, тогда как использование здесь «прототипа» явно говорит о части типа функции.

  3. §6.7.6.3 Деклараторы функций (включая прототипы)

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

  4. §6.9.1 / 7 Определения функций

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

    Здесь фраза «прототип функции», по-видимому, говорит о чем-то, связанном или содержащемся втип функции, но для которого декларатор функции может использоваться как прокси («служит как»).

Я полагаю, что это не будет соответствовать стандартам формальной строгости работы, такойкак Principia Mathematica , но это соответствует большинству юридических спецификаций и другим стандартам, в которых для толкования некоторых отрывков необходим здравый смысл.

Действительно, сама цитата, о которой идет речь:

"Прототип функции - это объявление функции, которая объявляет типы ее параметров."

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

Кроме того, если мы деконструируем §6.2.1 / 4 (цитируется частично ниже), мы видим, что он говорит, что:

Каждый другой идентификатор [то есть, кроме метки или имени макроса] имеет область действия, определяемую размещением его объявления (в описателе или спецификаторе типа).

и затем переходит кперечислите только три альтернативы для «объявления или спецификатора типа, который объявляет идентификатор»:

  1. «появляется вне любого блока или списка параметров»

  2. «появляется внутри блока» или «в списке объявлений параметров в определении функции»

  3. "появляется в списке объявлений параметров в прототипе функции (не входит в определение функции)"

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

Является ли это недостатком стандарта или нет, это вопрос мнения, в котором я не хочу участвовать.Я проверил то, что я считаю самым последним списком] (http://www.open -std.org / jtc1 / sc22 / wg14 / www / docs / n2244.htm ) и не нашел ничего значимого, посколькуЯ знаю, что об этом не сообщалось как о дефекте.


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

Что стандарт говорит о сфере примененияиз идентификаторов в списках параметров мне кажется вполне понятным.§6.2.1 / 4 определяет две возможные области действия для идентификаторов, объявленных в списке параметров (выделение выделено):

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

Если описатель или спецификатор типа, который объявляетидентификатор появляется в списке объявлений параметров в прототипе функции ( не входит в определение функции ), идентификатор имеет область действия прототипа функции , которая заканчивается в конце объявления функции.(§6.2.1 / 4)

В примере, о котором идет речь, декларатор struct s представляет собой параметр-list , который в точности является списком параметровдекларации».Таким образом, применяется второе предложение, и их область действия ограничивается самим списком параметров.Это делает struct практически бесполезным, поэтому компилятор предупреждает вас.

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

Я полагаю, что цель стандарта заключалась в том, чтобы объявление спецификаторов типов для теговых типов появлялось вне списков параметров.Это подтверждается языком § 6.7.2.3 (Теги):

  1. Контент определенного типа должен определяться не более одного раза.

А

Два объявления типов структуры, объединения или перечисления, которые находятся в разных областях или используют разные теги, объявляют разные типы.Каждое объявление типа структуры, объединения или перечислимого типа, которое не включает тег, объявляет отдельный тип.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...