typedef и struct в С

Тема в разделе "LANGS.C", создана пользователем XshStasX, 12 апр 2011.

  1. XshStasX

    XshStasX New Member

    Публикаций:
    0
    Регистрация:
    9 авг 2008
    Сообщения:
    991
    в чем разница между:
    Код (Text):
    1. typedef struct __mystruct{
    2.   //...
    3. }mystruct;
    4.  
    5. и
    6. struct mystruct{
    7.   //...
    8. };
    Смотрю исходники ядра линукса, и интересно почему там отдают предпочтение второму варианту.
    Первый ведь вариант удобней... так как не надо каждый раз дописывать struct перед объявлением переменной.
     
  2. r90

    r90 New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2005
    Сообщения:
    898
    Чтобы путаницы не было. typedef'ы только для примитивных типов. Объявление же локальной переменной структурного типа должно бросаться в глаза -- в ядре стек не резиновый.
     
  3. osox

    osox New Member

    Публикаций:
    0
    Регистрация:
    13 ноя 2009
    Сообщения:
    280
    ну в стиле БОЛЬШИМИ_БУКВАМИ_ИМЯ_ТИПА_СТРУКТУРЫ тоже сразу видно что на стеке не int переменная )))
     
  4. osox

    osox New Member

    Публикаций:
    0
    Регистрация:
    13 ноя 2009
    Сообщения:
    280
    например ядро винды использует все заглавные для структурного типа
    там правда за заглавными не только структурный тип но и примитивные типы
    скрываются что не очень понятно сразу что это если не в теме это
    вопрос стиля наверное
     
  5. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    XshStasX

    Нашел куда смотреть :)))
     
  6. r90

    r90 New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2005
    Сообщения:
    898
    osox
    В *nix не любят БОЛЬШИХ_БУКВ. =)
    Есть парочка исключений, типа FILE из stdio.h, но они больше похожи на историческую случайность.
     
  7. reverser

    reverser New Member

    Публикаций:
    0
    Регистрация:
    27 янв 2004
    Сообщения:
    615
    Если сделать так:
    Код (Text):
    1. typedef struct __mystruct{
    2.   //...
    3. }mystruct;
    То вместо
    Код (Text):
    1. struct __mystruct a;
    можно писать просто
    Код (Text):
    1. mystruct a;
    Для второго же случая
    Код (Text):
    1. struct mystruct{
    2.   //...
    3. };
    Придётся всегда выписывать struct полностью:
    Код (Text):
    1. struct mystruct a;
    Не забывай, что ядро линукса написано на C, а не C++.
     
  8. reversecode

    reversecode Guest

    Публикаций:
    0
    есть еще маааленький ньюанс
    может не совсем к ядру линукса (смотреть лень), но вообще к структуризации файлов типов данных итд

    для того что бы был виден typedef он должен быть в .h файла, и этот .h файл должен везде инклудится - что не всегда надо
    а для компиляции функции достаточно что бы компилятор опознал mystruct

    в таком виде к примеру mystruct *
    он конечно не опознает да и .h не инклудится
    поэтому ставят struct mystruct *
     
  9. osox

    osox New Member

    Публикаций:
    0
    Регистрация:
    13 ноя 2009
    Сообщения:
    280
    это делается еще для сокрытия реализации
    Код (Text):
    1. power.h
    2. typedef struct tagTYPE TYPE;
    3. //interface
    4. func0(TYPE *);
    5. func1(TYPE *);
    6. TYPE * create_power();
    Код (Text):
    1. power.c
    2. #include "power.h"
    3. struct tagTYPE
    4. {
    5.     ...
    6.     ...
    7. };
    Код (Text):
    1. client.c
    2. #include "power.h"
    3.  
    4. TYPE obj; // error undefined type used
    5. TYPE *Interface = create_power();
    6. func0(Interface,...);
     
  10. r90

    r90 New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2005
    Сообщения:
    898
    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):
    1. typedef struct tagNAME {
    2. } NAME;
    Вместо более очевидного
    Код (Text):
    1. typedef struct {
    2. } NAME;
    ?
    Все равно ведь после этого typedef'а никто и никогда не обращается к структуре по её истинному имени. А это имя засирает пространство имён, что особенно важно когда код пишется портабельный между C и C++: в C нет пространств имён, а C++ сваливает в одну кучу имена и типов, и констант/переменных/функций.
     
  11. osox

    osox New Member

    Публикаций:
    0
    Регистрация:
    13 ноя 2009
    Сообщения:
    280
    r90
    я говорю именно о сокрытии и согласен что можно обойтись и без typedef
    привычка наверное от чтения околовендовых исходников
    да согласен
    (немножко о областях и пространствах может кому-то пригодится)
    вообще в си одно пространство имен глобальное оно делится на 4 независимых пространств имен
    для разных групп идентификаторов
    в одной области видимости например в функции могуть прекрасно жить одинаковые идентификаторы
    обозначающие разные сущности в своем контексте применения пример
    Код (Text):
    1. struct name
    2. {
    3.     ... name;
    4. };
    5.  
    6. func0()
    7. {
    8.     struct name name;
    9.     name.name = ...;
    10.     goto name;
    11.     name:
    12. }
    да typdef вводит имена в 1) группу идентификаторов так как typedef объявления глобальны
    они могуть помешать нам в глобальной области видимости при создании функции с таким же именем
    или глобальной переменной или глобальной enum константы внутри функций любое локальное объявление идентификатора из 1) группы скроет глобальный typedef (просто локальная область видимости скрывает внешнюю это не обязательно глобальная при большой вложенности управляющих структур это может быть просто внешний цикл но скрываются не все идентификаторы а только из соответствующей группы смотря идентификатор из какой группы объявляется)
    Код (Text):
    1. typedef struct tagNAME {
    2. } NAME;
    Вместо более очевидного
    Код (Text):
    1. typedef struct {
    2. } NAME;
    не поэтому ?
    Код (Text):
    1. typedef struct {
    2.     wtf ?? *self;
    3. } NAME;
    4. --------
    5. typedef struct tagNAME {
    6.     struct tagNAME *self;
    7. } NAME;
    8. --------
    ну и еще в других местах где надо сделать forward declaration
    ?