В чем разница между декларатором и прямым декларатором?

В книге «Язык программирования C, 2-е издание» авторов Брайана В. Кернигана и Денниса М. Ритчи говорится о деклараторах и прямых деклараторах. Обсуждение начинается в книге на стр. 122 с dcl и direct-dcl Не могли бы вы объяснить разницу между декларатором и прямым декларатором простым и понятным способом? Что делает его прямым?

Также на с. 225

где direct-declarator является идентификатором или идентификатором в скобках. В частности, он не должен достигать типа функции с помощью typedef.

Мне кажется, что деклараторы — это объявление переменной или функции. В «TD» часть T указывает спецификаторы и типы, а часть D определяет идентификатор, то есть уникальное идентификационное имя переменной или функции. Это как-то связано с грамматикой языка.

Являются ли деклараторы косвенными, поскольку они не указаны как прямые, как в direct-declarator?

Смотрите синтаксическую диаграмму здесь

Barmar 01.02.2023 19:19

Различие действительно важно только для синтаксического анализа объявлений, на самом деле они не являются отдельными понятиями в языке. Термин «прямой декларатор» никогда не появляется за пределами синтаксической диаграммы.

Barmar 01.02.2023 19:21

@ Бармар, спасибо. Ваша диаграмма может быть полезна, когда я лучше знаком с темой, но я не понимаю синтаксическую диаграмму, и она не объясняет разницу между декларатором и прямым декларатором. Кроме того, я хочу понять грамматику. Я студент компьютерных наук.

Joshua Ginn 01.02.2023 19:38
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
5
3
91
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

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

Полное определение этих терминов можно найти в синтаксисе декларатора, который можно найти в разделе 6.7.6p1 стандарта C11:

декларатор:

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

прямой декларатор:

  • идентификатор
  • ( декларатор )
  • прямой-декларатор [ список-классификаторов-типовoptвыражение-присваиванияopt]
  • прямой-декларатор [static список-классификаторов-типовoptвыражение-присваивания ]
  • прямой-декларатор [ список-классификаторов-типов static выражение-присваивания ]
  • прямой-декларатор [ список-классификаторов-типовopt*]
  • прямой декларатор ( список типов параметров )
  • прямой-декларатор ( список-идентификаторовopt)

указатель:

  • * список-классификаторов-типовopt
  • * указатель-список-классификаторовopt

список-квалификаторов-типов:

  • квалификатор типа
  • список-квалификаторов-типов

список типов параметров:

  • список-параметров
  • список параметров ,...

список параметров:

  • объявление параметра
  • список-параметров , объявление-параметров

объявление параметра:

  • декларатор спецификаторов объявлений
  • спецификаторы объявления абстрактный деклараторopt

Даже второе издание K&R в наши дни представляет скорее исторический, чем практический интерес.

Тем не менее термины «декларатор» и «прямой декларатор» продолжают использоваться в текущей спецификации языка C. Спецификация языка описывает первый следующим образом:

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

(С17 6.7.6/2)

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

«Прямые деклараторы» — это подмножество деклараторов. «Прямой» предназначен для контраста с «косвенным», как в указателях. Например, учитывая

int i;
int *p;

Все i, *p и p являются синтаксическими деклараторами, но из них только i и p являются прямыми деклараторами. И только i и *p являются полными деклараторами, то есть теми, которые не появляются как часть другого декларатора (как это делает декларатор p).

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

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

Ответ принят как подходящий

Грамматике требуется токен прямого декларатора, чтобы указать приоритет. Как бы то ни было, * foo [ 3 ] должен анализироваться как декларатор, за которым следует * прямой декларатор, которым является foo [ 3 ]. Если бы грамматика не разделяла декларатор и прямой декларатор, было бы неясно, было ли это *, за которым следует foo [ 3 ], сгруппированное вместе, или * foo, сгруппированное вместе, за которым следует [ 3 ].

Грамматика говорит, что декларатор это:

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

где указатель — это *, за которым следуют необязательные квалификаторы (например, const), а прямой декларатор — один из:

  • идентификатор
  • ( декларатор )
  • прямой-декларатор [ список-классификаторов-типовoptвыражение-присваиванияopt]
  • прямой-декларатор [static список-классификаторов-типовoptвыражение-присваивания ]
  • прямой-декларатор [ список-классификаторов-типов static выражение-присваивания ]
  • прямой-декларатор [ список-классификаторов-типовopt * ]
  • прямой декларатор ( список типов параметров )
  • прямой-декларатор ( список-идентификаторовopt)

Итак, учитывая * foo [ 3 ], мы должны принять это как декларатор с * для указателя и foo [ 3 ] для прямого декларатора. Невозможно иметь * в начале прямого декларатора. Таким образом, * foo [ 3 ] должен объявлять массив из 3 указателей, а не указатель на массив из 3 элементов.

Если бы эти параметры для декларатора и прямого декларатора были объединены в один токен грамматики, то синтаксический анализ был бы неоднозначным. Вы можете проанализировать это как * foo [ 3 ], поскольку * foo является декларатором, за которым следует [ 3 ], а это не то, чего мы хотим.

Имя не имеет большого значения; нам просто нужно другое имя для дополнительного токена. Есть и другие примеры этого в грамматике Си. Примечательно, что грамматика выражений начинается с выражения, а затем проходит через цепочку выражения-присваивания, условного-выражения, логического-ИЛИ-выражения и так далее. У них есть имена, связанные с операторами, которые они включают, пока вы не доберетесь до первичного выражения. Это имеет некоторое семантическое сходство с direct-declarator, предполагая, что они оба названы в духе «хорошо, мы добрались до конца этой грамматической цепочки, вот первичный/прямой токен».

Это действительно помогло: «Это имеет некоторое семантическое сходство с direct-declarator, предполагая, что они оба названы в духе «хорошо, мы добрались до конца этой грамматической цепочки, вот первичный/прямой токен».

Joshua Ginn 02.02.2023 15:27

Другие вопросы по теме