Модераторы: bsa
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Объявления структур и перечислений 
:(
    Опции темы
Compositum
  Дата 8.2.2013, 21:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Senior developer
**


Профиль
Группа: Awaiting Authorisation
Сообщений: 430
Регистрация: 6.1.2008
Где: Санкт-Петербург

Репутация: нет
Всего: 1



Доброго времени суток. 

Пишу на C90. Создал три файла:
main.c, header.h и library.c.
В первом - точка входа, во втором - все необходимые объявления. В третьем - определения функций и static переменных, нужных для их работы.

Помимо функций, в library.c определены некоторые перечисления и структуры. 

Вопрос: как правильно в заголовочных файлах создавать объявления для перечислений и структур, определённых в др. файлах?

Спасибо.
PM   Вверх
feodorv
Дата 9.2.2013, 06:36 (ссылка) |    (голосов:2) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(Compositum @  8.2.2013,  22:50 Найти цитируемый пост)
как правильно в заголовочных файлах создавать объявления для перечислений и структур, определённых в др. файлах?

Всё завит от задачи и стиля программирования, которого Вы придерживаетесь  smile 

Структуры можно объявлять так (имя структуры - после тела структуры):
Код

typedef struct

  int field1;
  char *field2;
} my_struct;


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

Файл mystru.h
Код

#ifndef _MY_STRU_H_
#define _MY_STRU_H_

typedef struct

  int field1;
  char *field2;
} my_struct;

int manipulate( my_struct *ms );

#endif;


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

Но есть другой вариант (я его сторонник), когда имя структуры следует сразу за ключевым словом struct (перед телом структуры):
Код

struct _my_struct

  int field1;
  char *field2;
};

int manipulate( struct _my_struct *ms );


Правда тогда везде приходится таскать за собой это самое ключевое слово struct:
Код

int main( void )
{
  struct _my_struct myStruct;
  return manipulate( &myStruct );
}


Однако если мы имеем дело только с указателями на нашу структуру, то появляется прекрасная возможность объявлять функции или элементы других структур, не раскрывая тела нашей структуры!
Например:
Код

#ifndef _MY_STRU_H_
#define _MY_STRU_H_

struct _my_struct; // обязательно объявляем нашу структуру

struct _my_struct *createMyStruct( ...param list... );
int manipulate( struct _my_struct *ms );

struct _enother_struct
{
  struct _my_struct *mc;
  const char *name;
  unsigned int ip;
};

int enother_manipulate( struct enother_struct *es );

#endif


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


Очень часто структуре дают оба имени:
Код

typedef struct _my_struct

  int field1;
  char *field2;
} my_struct;

Тогда уже существует выбор - в каких-то участках кода использовать struct _my_struct, в каких-то my_struct.


Но если происходит наследование одной структуры от другой, то в этом случае знание содержимого структуры обязательно:
Код

#ifndef _ENOTHER_STRU_H_
#define _ENOTHER_STRU_H_

#include "my_stru.h"

struct enother_struct

  struct _my_struct; // мы обязаны знать устройство структуры
  int field1;
  char *field2;
};

int enother_manipulate( enother_struct *ms );

#endif;



Насчёт enum'ов. Не помню, что говорит стандарт на этот случай, но некоторые компиляторы переваривают подобное с перечислением:
Код

#ifndef _MY_STRU_H_
#define _MY_STRU_H_

enum my_enum; // само перечисление где-то в другом месте
void printMyEnum( enum my_enum );

#endif

Но многие не переваривают... Поэтому лучше всего задавать перечисления явно:
Код

enum
{
  white = 0,
  red = 3,
  blue = 6,
  green = 12
} color;

Или вообще не давать перечислению имя, а пользоваться им так, как будто просто задефайнил множество констант:
Код

enum
{
  nil,
  one,
  two,
  three,
  last
};

const char *str[last] = { "0", "1", "2", "3" };


Перечисления обычно определяются в заголовочных файлах (если они востребованы в разных модулях), но не исключено и определение в одном единственном c-файле, если оно только там и используется...

Это сообщение отредактировал(а) feodorv - 9.2.2013, 18:17


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
Compositum
Дата 9.2.2013, 10:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Senior developer
**


Профиль
Группа: Awaiting Authorisation
Сообщений: 430
Регистрация: 6.1.2008
Где: Санкт-Петербург

Репутация: нет
Всего: 1



Благодарю за расширенный ответ! Интересная информация.
Цитата

Структуры можно объявлять так (имя структуры - после тела структуры):...
Тогда Вы обязаны включить определение этой структуры в ту единицу трансляции...
То есть достаточно определение структуры поместить в заголовочный файл...

Вы случайно не смешиваете в данных случаях понятие "объявления" с понятием "определения"?

Изначально, вопрос моего топика был обусловлен тем, что я ошибочно (как оказалось) считал следующую запись ОПРЕДЕЛЕНИЕМ:
Код

struct

  int field1;
  char *field2;
} my_struct;
 
Поэтому я боялся, что разместив эту запись в заголовочном файле, я тем самым растиражирую ОПРЕДЕЛЕНИЕ структуры/перечисления по многим .c-файлам, в связи с чем ожидал возникновения проблем. Но, как оказалось, это на самом деле ОБЪЯВЛЕНИЕ. А раз так, то можно хранить его в заголовке, не опасаясь накладок. На http://stackoverflow.com мне пояснили, что я заблуждался на этот счёт. После этого, порывшись в "Язык программирования C" - нашёл тому подтверждение.

Цитата

Но если происходит наследование одной структуры от другой...

Насколько мне известно, в C нет наследования, поскольку это не объектно ориентированный язык. В приведённом вами коде, я не наблюдаю наследования, но вижу включение экземпляра одной структуры в объявление другой. Или я чего-то не понял?

Спасибо.
PM   Вверх
feodorv
Дата 9.2.2013, 16:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(Compositum @  9.2.2013,  11:24 Найти цитируемый пост)
Вы случайно не смешиваете в данных случаях понятие "объявления" с понятием "определения"?

Возможно. Но в русском языке употребляется и то и другое слово по отношению к "декларированию" структуры:
Код

struct xxxx
{
  ...
};

Кстати, это тоже "декларирование":
Код

struct xxxx;

А как по Вашему различаются эти два понятия в данном случае?


Цитата(Compositum @  9.2.2013,  11:24 Найти цитируемый пост)
что я ошибочно (как оказалось) считал следующую запись ОПРЕДЕЛЕНИЕМ:

Честно говоря, не договорившись о терминах, довольно трудно рассуждать об ошибочности... Пусть будет ОПРЕДЕЛЕНИЕ  smile 


Цитата(Compositum @  9.2.2013,  11:24 Найти цитируемый пост)
Поэтому я боялся, что разместив эту запись в заголовочном файле, я тем самым растиражирую ОПРЕДЕЛЕНИЕ структуры/перечисления по многим .c-файлам

Гм. А это проблема?
Вот если у вас где-то в с-файле уже определена структура с этим же именем, то это, да, проблема, компилятор заупрямится и не захочет оттранслировать этот c-файл.

Задайтесь вопросом: зачем программисты помещают определения структуры в заголовочных файлах? Что было бы, если бы они не давали определения структур?

Каждая единица трансляции в C (на то она и единица) использует свой набор определений типов переменных, не мешая другой единице трансляции. Поэтому если определение структуры, как Вы выражаетесь, "тиражируется" по разным единицам трансляции, то это нормально. Это самая обычная практика (у которой есть свои подводные камни, правда), но так, по-моему, и было изначально задумано. А вот если в одной и той же единице трансляции дано несколько определений структуры с одним и тем же именем, то тут всё зависит от компилятора и определения структур. Некоторые компиляторы сравнивают определения, и если они совпадают, то только выдают предупреждение, что структура определена дважды. Но многие компиляторы не позволяют таких вольностей (недавний пример), что, по-моему, более правильно. 


Цитата(Compositum @  9.2.2013,  11:24 Найти цитируемый пост)
Но, как оказалось, это на самом деле ОБЪЯВЛЕНИЕ.

Не вижу разницы. Например, декларирование вида
Код

struct xxxx;

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


Цитата(Compositum @  9.2.2013,  11:24 Найти цитируемый пост)
На http://stackoverflow.com мне пояснили

Увы, ссылка не о чём. Давайте ссылку на само обсуждение)))


Цитата(Compositum @  9.2.2013,  11:24 Найти цитируемый пост)
Насколько мне известно, в C нет наследования, поскольку это не объектно ориентированный язык. В приведённом вами коде, я не наблюдаю наследования, но вижу включение экземпляра одной структуры в объявление другой. Или я чего-то не понял?

Нет, не правильно. В приведённом коде
Цитата(feodorv @  9.2.2013,  07:36 Найти цитируемый пост)
struct enother_struct

  struct _my_struct; // мы обязаны знать устройство структуры
  int field1;
  char *field2;
};

нет ни одного экземпляра структуры))) Одно сплошное декларирование.

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

Это сообщение отредактировал(а) feodorv - 9.2.2013, 16:20


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
volatile
Дата 9.2.2013, 18:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 16
Всего: 85



Ребята, вы чего это?  smile 

Цитата(feodorv @  9.2.2013,  06:36 Найти цитируемый пост)
Очень часто структуре дают оба имени:
struct _my_struct

  int field1;
  char *field2;
} my_struct;


Это не оба имени, это:
1. Определение структуры
2. Объявление переменной, этого типа 

Синоним этого выглядит так:
Код

struct _my_struct

  int field1;
  char *field2;
};
struct _my_struct  my_struct;

Эта-же ошибка повторяецца и в других местах:
Цитата(feodorv @  9.2.2013,  06:36 Найти цитируемый пост)
Структуры можно объявлять так (имя структуры - после тела структуры):
struct

  int field1;
  char *field2;
} my_struct;

Это не имя структуры, это переменая!

PM MAIL   Вверх
feodorv
Дата 9.2.2013, 18:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(volatile @  9.2.2013,  19:29 Найти цитируемый пост)
Это не имя структуры, это переменая!

Не, не, я тоже заметил и поправил:
Код

typedef struct

  int field1;
  char *field2;
} my_struct;


Добавлено через 1 минуту и 25 секунд
Цитата(volatile @  9.2.2013,  19:29 Найти цитируемый пост)
struct

  int field1;
  char *field2;
} my_struct;

В Си такое не прокатывает)))


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
volatile
Дата 9.2.2013, 23:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 16
Всего: 85



Цитата(feodorv @ 9.2.2013,  18:41)
Цитата(volatile @  9.2.2013,  19:29 Найти цитируемый пост)
struct

  int field1;
  char *field2;
} my_struct;

В Си такое не прокатывает)))

Прокатывает.
(поправте еще раз  smile )





Это сообщение отредактировал(а) volatile - 9.2.2013, 23:37
PM MAIL   Вверх
feodorv
Дата 10.2.2013, 04:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(volatile @  10.2.2013,  00:29 Найти цитируемый пост)
Прокатывает.

 smile 
Да, старьё-компилятор проглотил не подавившись)))


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
volatile
Дата 10.2.2013, 11:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 16
Всего: 85



Цитата(feodorv @  10.2.2013,  04:28 Найти цитируемый пост)
Да, старьё-компилятор проглотил 

причем здесь старье не-старье?

Цитата(Compositum @ 9.2.2013,  10:24)
Изначально, вопрос моего топика был обусловлен тем, что я ошибочно (как оказалось) считал следующую запись ОПРЕДЕЛЕНИЕМ:
Код

struct

  int field1;
  char *field2;
} my_struct;
 
Поэтому я боялся, что разместив эту запись в заголовочном файле, я тем самым растиражирую ОПРЕДЕЛЕНИЕ структуры/перечисления по многим .c-файлам,

Compositum, это не определение структуры.
Это объявление переменной, типа безымянной структуры.
обычно такая запись делаецца, когда нужна одна такая переменная.
К определению типа структуры это никакого отношения не имеет.
И имхо должно работать как в старых, так и новых компиляторах С.
Потому как это основы языка.

В С заголовок такую конструкцию помещать, имхо, можно.
В плюсах, кстати нельзя.

(впрочем я не глубокий знаток чистого С, пишу на плюсах.)


PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Для новичков"
JackYF
bsa

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.0804 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.