Как эффективно структурировать C-программу - PullRequest
28 голосов
/ 07 июня 2009

Позвольте мне сначала сказать, что у меня достаточно опыта как в C, так и в C ++. Тем не менее, я начинаю новый проект на C и работаю с объектно-ориентированными языками так долго (C # и C ++), что у меня возникают проблемы с эффективным способом инкапсуляции функциональности в процедурном языке. Моей первой мыслью было просто прибегнуть к своим ОО-знаниям и структурировать их примерно так:

struct Foo 
{
    int x;
    char *y;
}; 

struct Foo *new_Foo()
{
    return (struct Foo *)malloc(sizeof(struct Foo));
} 

void Foo_member_function(struct Foo *foo, int z)
{
    foo->x = z;    
}

Но это только кажется утомительным и противоречит духу C. Не говоря уже о том, что это ОО бедняка.

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

Указатели на соответствующие статьи и книги также допустимы.

Ответы [ 7 ]

16 голосов
/ 07 июня 2009

Это вполне нормальная и разумная практика. Но старайтесь не показывать структуру структуры в заголовочных файлах, чтобы у вас была некоторая гибкость в том, как она реализована, и лучше управляйте своими зависимостями.

Подробнее см. Непрозрачный указатель .

12 голосов
/ 07 июня 2009

То, что вы предлагаете, это то, как я всегда писал программы на С в те времена, когда я делал такие вещи. Я не думаю, что это "OO бедняков", я думаю, что это разумная практика процедурного программирования.

Я бы заметил пару вещей о вашем коде C:

  • используйте typedefs с определениями структуры, чтобы вам не нужно было разбрасывать ключевое слово struct по всему коду
  • использовать приведение только тогда, когда оно действительно необходимо - приведение к возвращаемому значению от malloc () не требуется
3 голосов
/ 07 июня 2009

Это довольно разумный способ написать программу на Си. Существует еще одно большое приложение, которое выполняет почти те же функции - ядро ​​Linux. Некоторые почти OO-функции, используемые там:

  • структуры и операции над структурами для инкапсуляции, как в вашем примере
  • указатели на базовые структуры как форма наследства бедняков - вы найдете множество там ссылки на struct kobject
  • макросы для генерации функций вместо замены шаблонов
3 голосов
/ 07 июня 2009

Хммм ... Раньше мы просто использовали соглашения о присвоении имен ... Ergo: str * что с какой общей структурой данных? Так что, может быть, просто взять синтаксис C # и s /./_/ g?

  • foo_constructor
  • foo_destructor
  • foo_someMethod
  • foo_someMethod2 // нет перегрузки в ANSI C
  • foo_otherMethod

... и нет наследства ...

  • foo2_constructor
  • foo2_destructor
  • foo2_someMethod // и полиморфизма нет

Но посмотрите на светлую сторону ... вы можете использовать указатель на указатель на указатель на функцию, возвращающий указатель на указатель-int! О, радость!

Мой лучший совет - выучить уроки Java (и с помощью логического вывода C #) и структурировать свои библиотеки так, чтобы они НЕ имели побочных эффектов ... больше typdefs == меньше головных болей ... и, если вам нужно, следовать этот мудрец посоветуйте, пожалуйста, дайте мне знать; -)

Приветствия. Кит.

1 голос
/ 07 июня 2009

Я согласен с предложениями выше. Вы делаете это наилучшим образом ... если вы хотите программировать на C.

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

Но здесь у нас есть простой компилятор C ++ to C. Почему бы не просто программировать на C ++, использовать настоящий компилятор C ++, использовать чистые интерфейсы и просто связать код C ++ с кодом C? По какой причине вам все равно нужно писать код на C или C ++? Или, если вам нужно, сгенерируйте код C из компилятора и скомпилируйте выходной код C вместе со всем, что вам нужно.

1 голос
/ 07 июня 2009

C был языком низкого уровня, и в этом отношении было бы очень полезно организовать ваши структуры данных в соответствии с вашими функциями кода и модулями.

Я бы посоветовал вам использовать typedefs и перечисления везде, где вы хотите создавать объекты данных. Используйте макросы или статические функции для инициализации, выделения и «уничтожения» по мере необходимости.

0 голосов
/ 07 июня 2009

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

struct klass {
  char * value;

  void (*set_value) (struct klass *, const char *);
  void (*destroy) (struct klass *);
};

static void
klass_method_set_value (struct klass * k, const char * value) {
  if (k->value == NULL) {
  }
}

static void 
klass_object_desetroy (struct klass * k) {
  free (k);
  k = NULL;
}

static void
klass_method_destroy (struct klass * k) {
  klass_object_destroy (k);
}

static struct klass *
klass_object_init (void) {
  struct klass * obj = (struct klass *) malloc (sizeof (struct klass*) );

  /* members */
  obj->value = NULL;

  /* methods */
  obj->set_value = klass_method_set_value;
  obj->destroy = klass_method_destroy;
  return obj;
}

struct klass * 
klass_new (void) {
  return klass_object_init ();
}

Простите, если что-то не так; написал это немного быстро.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...