В книге «Язык программирования C, 2-е издание» авторов Брайана В. Кернигана и Денниса М. Ритчи говорится о деклараторах и прямых деклараторах. Обсуждение начинается в книге на стр. 122 с dcl и direct-dcl Не могли бы вы объяснить разницу между декларатором и прямым декларатором простым и понятным способом? Что делает его прямым?
Также на с. 225
где direct-declarator является идентификатором или идентификатором в скобках. В частности, он не должен достигать типа функции с помощью typedef.
Мне кажется, что деклараторы — это объявление переменной или функции. В «TD» часть T указывает спецификаторы и типы, а часть D определяет идентификатор, то есть уникальное идентификационное имя переменной или функции. Это как-то связано с грамматикой языка.
Являются ли деклараторы косвенными, поскольку они не указаны как прямые, как в direct-declarator?
Различие действительно важно только для синтаксического анализа объявлений, на самом деле они не являются отдельными понятиями в языке. Термин «прямой декларатор» никогда не появляется за пределами синтаксической диаграммы.
@ Бармар, спасибо. Ваша диаграмма может быть полезна, когда я лучше знаком с темой, но я не понимаю синтаксическую диаграмму, и она не объясняет разницу между декларатором и прямым декларатором. Кроме того, я хочу понять грамматику. Я студент компьютерных наук.





Грубо говоря, декларатор — это полное объявление, в то время как прямой декларатор — это либо идентификатор сам по себе, либо идентификатор, за которым следует [] (делает его массивом) или () (делает функцию или указатель на функцию).
Полное определение этих терминов можно найти в синтаксисе декларатора, который можно найти в разделе 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 ].
Грамматика говорит, что декларатор это:
где указатель — это *, за которым следуют необязательные квалификаторы (например, const), а прямой декларатор — один из:
( декларатор )[ список-классификаторов-типовoptвыражение-присваиванияopt][static список-классификаторов-типовoptвыражение-присваивания ][ список-классификаторов-типов static выражение-присваивания ][ список-классификаторов-типовopt * ]( список типов параметров )( список-идентификаторовopt)Итак, учитывая * foo [ 3 ], мы должны принять это как декларатор с * для указателя и foo [ 3 ] для прямого декларатора. Невозможно иметь * в начале прямого декларатора. Таким образом, * foo [ 3 ] должен объявлять массив из 3 указателей, а не указатель на массив из 3 элементов.
Если бы эти параметры для декларатора и прямого декларатора были объединены в один токен грамматики, то синтаксический анализ был бы неоднозначным. Вы можете проанализировать это как * foo [ 3 ], поскольку * foo является декларатором, за которым следует [ 3 ], а это не то, чего мы хотим.
Имя не имеет большого значения; нам просто нужно другое имя для дополнительного токена. Есть и другие примеры этого в грамматике Си. Примечательно, что грамматика выражений начинается с выражения, а затем проходит через цепочку выражения-присваивания, условного-выражения, логического-ИЛИ-выражения и так далее. У них есть имена, связанные с операторами, которые они включают, пока вы не доберетесь до первичного выражения. Это имеет некоторое семантическое сходство с direct-declarator, предполагая, что они оба названы в духе «хорошо, мы добрались до конца этой грамматической цепочки, вот первичный/прямой токен».
Это действительно помогло: «Это имеет некоторое семантическое сходство с direct-declarator, предполагая, что они оба названы в духе «хорошо, мы добрались до конца этой грамматической цепочки, вот первичный/прямой токен».
Смотрите синтаксическую диаграмму здесь