в чем разница между: Код (Text): typedef struct __mystruct{ //... }mystruct; и struct mystruct{ //... }; Смотрю исходники ядра линукса, и интересно почему там отдают предпочтение второму варианту. Первый ведь вариант удобней... так как не надо каждый раз дописывать struct перед объявлением переменной.
Чтобы путаницы не было. typedef'ы только для примитивных типов. Объявление же локальной переменной структурного типа должно бросаться в глаза -- в ядре стек не резиновый.
например ядро винды использует все заглавные для структурного типа там правда за заглавными не только структурный тип но и примитивные типы скрываются что не очень понятно сразу что это если не в теме это вопрос стиля наверное
osox В *nix не любят БОЛЬШИХ_БУКВ. =) Есть парочка исключений, типа FILE из stdio.h, но они больше похожи на историческую случайность.
Если сделать так: Код (Text): typedef struct __mystruct{ //... }mystruct; То вместо Код (Text): struct __mystruct a; можно писать просто Код (Text): mystruct a; Для второго же случая Код (Text): struct mystruct{ //... }; Придётся всегда выписывать struct полностью: Код (Text): struct mystruct a; Не забывай, что ядро линукса написано на C, а не C++.
есть еще маааленький ньюанс может не совсем к ядру линукса (смотреть лень), но вообще к структуризации файлов типов данных итд для того что бы был виден typedef он должен быть в .h файла, и этот .h файл должен везде инклудится - что не всегда надо а для компиляции функции достаточно что бы компилятор опознал mystruct в таком виде к примеру mystruct * он конечно не опознает да и .h не инклудится поэтому ставят struct mystruct *
это делается еще для сокрытия реализации Код (Text): power.h typedef struct tagTYPE TYPE; //interface func0(TYPE *); func1(TYPE *); TYPE * create_power(); Код (Text): power.c #include "power.h" struct tagTYPE { ... ... }; Код (Text): client.c #include "power.h" TYPE obj; // error undefined type used TYPE *Interface = create_power(); func0(Interface,...);
osox Ты говоришь про полиморфизм, или именно про сокрытие реализации? Говоря о полиморфизме, я имею в виду то, что воспользовавшись typedef мы можем использовать любой из наших типов не задумываясь о том, что он из себя представляет -- примитивный тип, структуру, union, enum. Мы просто пишем "имя_типа имя_переменной;". Но в C (а может и в C++ тоже) такой полиморфизм -- глупость. Он ровным счётом ничего не даст. Он лишь может привнести лишнюю неразбериху в определённых ситуациях. Если уж мы позволили себе ошибиться в выборе "метатипа" для типа, и назвали union'ом то, что должно быть структурой, то после исправления ошибки проектирования и правки заголовка, нам по-любому придётся проводить аудит всего кода на предмет того, чтобы тип и переменные этого типа использовались бы правильно. А такой аудит проще всего проводить по следам из еггогов компилятора. А если речь о сокрытии реализации, то если из твоего когда вырезать подстроку "typedef struct tagTYPE", а все подстроки TYPE заменить на "struct tagTYPE", то код будет вполне рабочим. То есть для сокрытия typedef не нужен. Единственное, известное мне, преимущество использования typedef для union'ов, struct'ов, и enum'ов -- это сокращение записи. Недостатков же, я вижу два: 1. Снижение информативности кода. Допустим гипотетическую ситуацию: Линус Торвальдс разглядывает присланный ему патч на ядро. Этот патч привносит в ядро две строки, и ещё в нём есть шесть строк "контекста" -- три неизменяемых строки до этих двух, и три -- после. Итого 8 строк кода. До Линуса за последний час дошло 20 патчей, у него нет времени, искать у себя на диске неизменённую последнюю версию ядра из git, чтобы примерить к ней патч, у него нет даже времени на то, чтобы примерить этот патч. Торвальдс должен прочитав восемь строк и подумав 30 секунд сказать либо "signed", либо "садись, два. завтра пересдача." Торвальдс -- не ЭВМ, и помнить ~12 мегастрок кода ядра он не может, и он не имеет никакой возможности угадать что такое TYPE: это struct, union или просто int под новым именем. Это может быть не столь существенно если речь идёт об объявлении локальной переменной, а если речь идёт о добавлении поля в широкоиспользуемую структуру? 2. Второй же недостаток typedef'а в том, что имена структур оказываются в одном пространстве имён с именами переменных. И работая в контексте ядра, когда в любом месте любого сорца этих имён сотни или даже тысячи, крайне сложно не войти в конфликт. И одно дело, бояться этих конфликтов при написании .h файла, и совсем другое если паника охватывает уже при одной мысли о заурядном объявлении локальной переменной. ps. У меня есть встречный вопрос. Кодерам вендовс посвящается. Почему в вендовс, используя typedef на каждую структуру, все пишут: Код (Text): typedef struct tagNAME { } NAME; Вместо более очевидного Код (Text): typedef struct { } NAME; ? Все равно ведь после этого typedef'а никто и никогда не обращается к структуре по её истинному имени. А это имя засирает пространство имён, что особенно важно когда код пишется портабельный между C и C++: в C нет пространств имён, а C++ сваливает в одну кучу имена и типов, и констант/переменных/функций.
r90 я говорю именно о сокрытии и согласен что можно обойтись и без typedef привычка наверное от чтения околовендовых исходников да согласен (немножко о областях и пространствах может кому-то пригодится) вообще в си одно пространство имен глобальное оно делится на 4 независимых пространств имен для разных групп идентификаторов в одной области видимости например в функции могуть прекрасно жить одинаковые идентификаторы обозначающие разные сущности в своем контексте применения пример Код (Text): struct name { ... name; }; func0() { struct name name; name.name = ...; goto name; name: } да typdef вводит имена в 1) группу идентификаторов так как typedef объявления глобальны они могуть помешать нам в глобальной области видимости при создании функции с таким же именем или глобальной переменной или глобальной enum константы внутри функций любое локальное объявление идентификатора из 1) группы скроет глобальный typedef (просто локальная область видимости скрывает внешнюю это не обязательно глобальная при большой вложенности управляющих структур это может быть просто внешний цикл но скрываются не все идентификаторы а только из соответствующей группы смотря идентификатор из какой группы объявляется) Код (Text): typedef struct tagNAME { } NAME; Вместо более очевидного Код (Text): typedef struct { } NAME; не поэтому ? Код (Text): typedef struct { wtf ?? *self; } NAME; -------- typedef struct tagNAME { struct tagNAME *self; } NAME; -------- ну и еще в других местах где надо сделать forward declaration ?