Как вы читаете объявления C? - PullRequest
       27

Как вы читаете объявления C?

41 голосов
/ 18 сентября 2008

Я слышал о некоторых методах, но ни один из них не застрял. Лично я стараюсь избегать сложных типов в C и пытаюсь разбить их на компонент typedef.

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

Как вы читаете сложные объявления C?

Ответы [ 10 ]

32 голосов
/ 18 сентября 2008

В этой статье объясняются относительно простые 7 правил, которые позволят вам прочитать любое объявление C, если вы захотите или хотите сделать это вручную: http://www.ericgiguere.com/articles/reading-c-declarations.html

  1. Найти идентификатор. Это ваша отправная точка. На листе бумаги напишите «объявить идентификатор как».
  2. Посмотрите направо. Если там ничего нет или есть правильная скобка ")", перейдите к шагу 4.
  3. Теперь вы находитесь в дескрипторе массива (левая скобка) или функции (левая скобка). Их может быть последовательность, заканчивающаяся либо несоответствующей правой круглой скобкой, либо концом объявления (точка с запятой или «=» для инициализации). Для каждого такого дескриптора, читая слева направо:

    • если пустой массив "[]", напишите "массив"
    • если массив с размером, напишите "размер массива"
    • если функция "()", напишите "функция, возвращающая"

    Остановитесь в непревзойденных скобках или в конце объявления, в зависимости от того, что произойдет раньше.

  4. Вернитесь в исходное положение и посмотрите налево. Если там ничего нет или есть левая скобка "(", перейдите к шагу 6. ​​
  5. Теперь вы находитесь в дескрипторе указателя "*". Это может быть последовательность слева, заканчивающаяся либо непревзойденной левой круглой скобкой "(", либо началом объявления. Чтение справа налево, для каждого дескриптора указателя напишите "указатель на". начало объявления, в зависимости от того, что будет первым.
  6. На данный момент у вас есть выражение в скобках или полный декларатор. Если у вас есть выражение в скобках, рассмотрите его как новую отправную точку и вернитесь к шагу 2.
  7. Запишите спецификатор типа. Стоп.

Если у вас все в порядке с инструментом, я предлагаю второе предложение программы cdecl: http://gd.tuwien.ac.at/linuxcommand.org/man_pages/cdecl1.html

22 голосов
/ 18 сентября 2008

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

  • Начните с идентификатора.
  • Идите прямо к нему справа.
  • Затем двигайтесь по часовой стрелке и переходите на левую сторону.
  • Двигайтесь по часовой стрелке и двигайтесь вправо.
  • Делайте это, пока объявление не было проанализировано полностью.

Есть дополнительное мета-правило, о котором нужно позаботиться:

  • Если есть скобки, завершите каждый уровень скобок, прежде чем выйти.

Здесь «идти» и «двигаться» означает читать символ там. Правила для этого:

  • * - указатель на
  • () - функция, возвращающая
  • (int, int) - функция, принимающая два целых и возвращающая
  • int, char и т. Д. - int, char и т. Д.
  • [] - массив
  • [10] - массив из десяти
  • и т.д.

Так, например, int* (*xyz[10])(int*, char) читается как:

xyz является

массив из десяти

указатель на

функция, принимающая int * и char и возвращающая

int *

6 голосов
/ 18 сентября 2008

Одно слово: cdecl

Черт, побил на 15 секунд!

4 голосов
/ 18 сентября 2008

Cdecl (и c ++ decl) - это программа для кодирования и декодирования объявлений типа C (или C ++).

http://gd.tuwien.ac.at/linuxcommand.org/man_pages/cdecl1.html

3 голосов
/ 18 сентября 2008

Когда я делал C, я использовал программу под названием "cdecl". Похоже, что он находится в Ubuntu Linux в пакете cutils или cdecl и, вероятно, доступен в другом месте.

1 голос
/ 27 мая 2011

Существует также веб-версия cdecl , которая довольно приятна.

1 голос
/ 18 сентября 2008

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» есть целая глава, озаглавленная «Расшифровка объявлений в C.

0 голосов
/ 05 декабря 2009

Только что натолкнулся на светящийся раздел в " Развитие языка Си ":

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

int i, *pi, **ppi;

объявлять целое число, указатель на целое число, указатель на указатель на целое число. Синтаксис этих объявлений отражает наблюдение, что все i, * pi и ** ppi дают тип int при использовании в выражении. Аналогичным образом,

int f(), *f(), (*f)();

объявить функцию, возвращающую целое число, функцию, возвращающую указатель на целое число, указатель на функцию, возвращающую целое число;

int *api[10], (*pai)[10];

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

0 голосов
/ 20 сентября 2008

Автоматизированное решение - cdecl.

Как правило, вы объявляете переменную так, как вы ее используете. Например, вы разыменовываете указатель p как в:

char c = * p

Вы объявляете это аналогичным образом:

char * p;

То же самое относится и к волосатым указателям на функции. Давайте объявим f как старый добрый «указатель на функцию, возвращающую указатель на int», а внешнее объявление просто смешно Это указатель на функцию, поэтому мы начнем с:

extern * f();

Возвращает указатель на int, поэтому где-то впереди есть

extern int * * f(); // XXX not quite yet

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

extern (int *)(* f)();

Объявите, как вы это используете.

0 голосов
/ 18 сентября 2008

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

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

...