Подтвердить что ты не робот

Как вы читаете декларации C?

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

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

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

4b9b3361

Ответ 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 секунд!

Ответ 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

Ответ 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];

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