Как читать сложные декларации C/C++ |
Добавил(а) microsin |
Декларации C иногда могут быть весьма сложными для чтения и понимания. Хочется выражаться нехорошими словами, выть и пинать стулья, когда видишь некоторые "простые" с виду выражения. При проведении собеседований в приеме на работу тоже часто любят задавать кандидатам каверзные вопросы такого рода (что ИМХО довольно глупо, но тут ничего поделать нельзя). int (*p)[5]; char *x[3][4]; int *(*a[10])(); int (*t[])(); Никогда не забуду головную боль при просмотре чужого кода, пока наконец не уяснил для себя правило перевода деклараций C на простой и понятный английский язык (здесь приведен перевод статьи [1]). По-другому эту проблему никак не решить - должно быть тупое правило, которое поможет прочитать любое объявление C, иначе будете все время наступать на одни и те же грабли. Вот хорошее правило, помогающее понять декларации C: Начните с имени переменной, также известного как идентификатор (оно всегда присутствует в декларации). Не пропуская правую круглую скобку, посмотрите направо и скажите, то видите - даже если ничего дальше не продолжается. Без пропуска левой скобки снова посмотрите налево, и скажите, что Вы видите. Если Вы все еще находитесь внутри пары круглых скобок, выйдите наружу с этого уровня. Посмотрите направо и скажите, что Вы видите. Посмотрите налево и скажите, что Вы видите. Делайте все это, пока не дойдете до типа переменной или возвращаемого типа. Важное замечание: Вы всегда должны помнить, что функции и массивы читаются слева направо и имеют приоритет перед указателями, которые читаются справа налево. Возможно, что пока все это кажется абракадаброй, но когда рассмотрим примеры, то все станет понятно. Для первого примера мы начинаем с имени p. Смотрим направо и натыкаемся на скобку, которую не хотим пропускать пока не посмотрим влево. Итак, смотрим влево до скобки и видим, что p это у нас указатель. Теперь мы можем выйти из круглых скобок и посмотреть направо, и мы видим, что это массив из 5 ячеек, теперь мы можем добавить это к нашей предыдущей информации - получается, что у нас массив из 5 указателей. Теперь мы смотрим влево и видим int, обозначающее целое число типа int. Добавив это к предыдущей полученной информации, получим следующее: "указатель на массив из 5 int". Для второго примера мы начинаем с имени x. Смотрим направо, и видим массив, составленный из 3 массивов размера 4. Вы возможно захотели бы вернуться стазу налево после того, как прочитали "массив размера 3", но этого делать нельзя, потому что следует помнить, что массивы имеют приоритет над указателями, так что надо читать справа дальше, и получить информацию о втором массиве. Итак, мы увидели, что x это двумерный массив, который состоит из 3 массивов размера 4, и теперь мы можем перейти налево. Смотрим налево от x и видим, что это указатель на char. В результате получается: "x это массив, составленный из 3 массивов, в каждом из которых 4 указателя на char". Для последних двух примеров будут просто даны ответы, потренируйтесь получить их самостоятельно. В третьем примере это "переменная a это массив из 10 указателей на такие функции, которые не принимают аргументов и возвращают указатель на int". Для четвертого примера: "массив указателей неопределенного размера на такие функции, который не принимают аргументов и возвращают значение int". [Ссылки] 1. Given the following complex C declarations, what does each one mean? site:programmerinterview.com. |