Как вы читаете декларации C?
Я слышал о некоторых методах, но никто из них не застрял. Лично я стараюсь избегать сложных типов в C и пытаюсь разбить их на компонент typedef.
Теперь я столкнулся с сохранением некоторого унаследованного кода от так называемого "трехзвездочного программиста", и мне трудно читать некоторые из *** кода [] [].
Как вы читаете сложные объявления C?
Ответы
Ответ 1
В этой статье объясняются относительно простые 7 правил, которые позволят вам прочитать любое объявление C, если вы захотите или хотите сделать это вручную: http://www.ericgiguere.com/articles/reading-c-declarations.html
- Найдите идентификатор. Это ваша отправная точка. На листе бумаги напишите "объявить идентификатор как".
- Посмотрите направо. Если там ничего нет или есть правильная скобка ")", перейдите к шагу 4.
-
Теперь вы находитесь либо на дескрипторе массива (левая скобка), либо на функции (левая скобка). Может быть последовательность из них, заканчивающаяся либо несогласованной правой скобкой, либо концом декларатора (точка с запятой или "=" для инициализации). Для каждого такого дескриптора, читающего слева направо:
- если пустой массив "[]", напишите "массив"
- Если массив с размером, напишите "размер массива"
- если функция "()", напишите "функция return"
Стоп в несогласованной скобке или в конце объявления, в зависимости от того, что наступит раньше.
- Вернитесь в исходное положение и посмотрите влево. Если там ничего нет или есть левая скобка "(", goto step 6.
- Теперь вы находитесь на дескрипторе указателя "*". Там может быть последовательность из них влево, заканчивающаяся либо непревзойденной левой скобкой "(" или начало декларатора. Чтение справа налево, для каждого указателя дескриптора пишут "указатель на". Остановить в несогласованной скобке или начало декларатора, в зависимости от того, что наступит раньше.
- В этот момент у вас есть либо выражение в скобках, либо полный декларатор. Если у вас есть выражение в скобках, рассмотрите его как новую отправную точку и вернитесь к шагу 2.
- Запишите спецификатор типа. Стоп.
Если у вас все в порядке с инструментом, то я второй предлагаю использовать программу cdecl
: http://gd.tuwien.ac.at/linuxcommand.org/man_pages/cdecl1.html
Ответ 2
Я обычно использую то, что иногда называют "правым правилом по часовой стрелке".
Это происходит следующим образом:
- Начните с идентификатора.
- Перейдите прямо к нему.
- Затем двигайтесь по часовой стрелке и идите в левую сторону.
- Двигайтесь по часовой стрелке и идите в правую сторону.
- Сделайте это до тех пор, пока декларация не будет полностью проанализирована.
Есть дополнительное мета-правило, о котором нужно позаботиться:
- Если есть круглые скобки, завершите каждый уровень круглых скобок, прежде чем перемещаться.
Здесь "движение" и "перемещение" где-то означает чтение символа. Правила для этого:
-
*
- указатель на
-
()
- возврат функции
-
(int, int)
- функция, принимающая два ints и возвращающая
-
int
, char
и т.д. - int
, char
и т.д.
-
[]
- массив
-
[10]
- массив из десяти
- и др.
Итак, например, int* (*xyz[10])(int*, char)
читается как:
xyz является
массив из десяти
указатель на
взяв int * и a char и возвращая
a int *
Ответ 3
Одно слово: cdecl
Проклятье, избитое на 15 секунд!
Ответ 4
http://eli.thegreenplace.net/2008/07/18/reading-c-type-declarations/
Ответ 5
Cdecl (и С++ decl) - это программа для кодирования и декодирования объявлений типа C (или С++).
http://gd.tuwien.ac.at/linuxcommand.org/man_pages/cdecl1.html
Ответ 6
Когда я делал C, я использовал программу под названием "cdecl". Похоже, что это в Ubuntu Linux в пакете cutils или cdecl, и он, вероятно, доступен в другом месте.
Ответ 7
cdecl предлагает интерфейс командной строки, поэтому дайте ему попробовать:
cdecl> explain int ***c[][]
declare c as array of array of pointer to pointer to pointer to int
другой пример
explain int (*IMP)(ID,SEL)
declare IMP as pointer to function (ID, SEL) returning int
Однако есть целая глава об этом в книге "C Deep Secrets", названной "Unscrambling declarations in C.
Отношения
Friedrich
Ответ 8
Также существует веб-версия cdecl, которая довольно гладкая.
Ответ 9
Общие проблемы с читабельностью включают в себя указатели на функции и тот факт, что массивы действительно являются указателями и что многомерные массивы - это действительно одномерные массивы (которые действительно являются указателями). Надеюсь, что это помогает.
В любом случае, всякий раз, когда вы понимаете декларации, возможно, вы можете найти способ упростить их, чтобы сделать их более читаемыми для следующего парня.
Ответ 10
Автоматическое решение - cdecl.
В общем, вы объявляете переменную так, как вы ее используете. Например, вы разыскиваете указатель p как:
char c = * p
вы заявляете это аналогичным образом:
char * p;
То же самое касается волосатых указателей функций. Пусть объявляет f хорошим старым "указателем на функцию, возвращающим указатель на int", и внешнюю декларацию просто смешно. Это указатель на функцию, поэтому мы начинаем с:
extern * f();
Он возвращает указатель на int, поэтому где-то там есть
extern int * * f(); // XXX not quite yet
Теперь, какая правильная ассоциативность? Я никогда не помню, поэтому используйте скобки.
extern (int *)(* f)();
Объявите его так, как вы его используете.
Ответ 11
Прочитайте справа налево.
***code[][]
- code [] [] является многомерным массивом
- * code [] [] является многомерным указателем массива
- ** code [] [] является многомерным указателем массива на указатель
- *** code [] [] является многомерным указателем массива на указатель на указатель
Ответ 12
Просто наткнулся на освещающий раздел в разделе "" Развитие языка C":
Для каждого объекта такого скомпонованного типа уже существует способ указать базовый объект: индексировать массив, вызывать функцию, использовать оператор указателя на указателе. Аналогичные рассуждения привели к синтаксису объявления для имен, отражающих синтаксис выражения, в котором обычно появляются имена. Таким образом,
int i, *pi, **ppi;
объявить целое число, указатель на целое число, указатель на указатель на целое число. Синтаксис этих объявлений отражает наблюдение, что i, * pi и ** ppi все дают тип int при использовании в выражении. Аналогично,
int f(), *f(), (*f)();
объявить функцию, возвращающую целое число, функцию, возвращающую указатель на целое число, указатель на функцию, возвращающую целое число;
int *api[10], (*pai)[10];
объявить массив указателей на целые числа и указатель на массив целых чисел. Во всех этих случаях объявление переменной напоминает ее использование в выражении, тип которого является именем, указанным во главе объявления.