Как программист на C++ должен разработать программное обеспечение в C? [закрытый]

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

Новые строки обычно создаются с символом \n, но также могут быть сделаны с \r\n (из файлов, сохраненных в Windows).

Решения

1. componentsSeparatedByCharactersInSet

let multiLineString = "Line 1\nLine 2\r\nLine 3\n"
let newlineChars = NSCharacterSet.newlineCharacterSet()
let lineArray = multiLineString.componentsSeparatedByCharactersInSet(newlineChars).filter{![110].isEmpty}
// "[Line 1, Line 2, Line 3]"

Если бы filter не использовалось, то \r\n выдает пустой элемент массива, потому что он считается как два символа и поэтому разделяет строку дважды в одном месте .

[Тысяча сто тридцать одна] [1 137] 2. split

let multiLineString = "Line 1\nLine 2\r\nLine 3\n"
let newlineChars = NSCharacterSet.newlineCharacterSet()
let lineArray = multiLineString.utf16.split { newlineChars.characterIsMember([111]) }.flatMap(String.init)
// "[Line 1, Line 2, Line 3]"

или

let multiLineString = "Line 1\nLine 2\r\nLine 3\n"
let lineArray = multiLineString.characters.split { [112] == "\n" || [112] == "\r\n" }.map(String.init)
// "[Line 1, Line 2, Line 3]"

Здесь \r\n учитывается как один символ Swift (расширенный кластер графем)

3. enumerateLines

let multiLineString = "Line 1\nLine 2\r\nLine 3\n"
var lineArray = [String]()
multiLineString.enumerateLines { (line, stop) -> () in
    lineArray.append(line)
}
// "[Line 1, Line 2, Line 3]"

Подробнее о синтаксисе enumerateLine см. Также в этот ответ .

Примечания:

  • многострочная строка обычно не смешивает \r\n и \n, но я делаю это здесь, чтобы показать, что эти методы могут обрабатывать оба формата.
  • NSCharacterSet.newlineCharacterSet() - символы новой строки, определенные как (U + 000A – U + 000D, U + 0085), которые включают в себя \r и \n.
  • Этот ответ является кратким изложением ответов на мой предыдущий вопрос . Прочитайте эти ответы для более подробной информации.
  • [+1139]

9
задан Community 23 May 2017 в 12:17
поделиться

14 ответов

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

31
ответ дан 4 December 2019 в 05:52
поделиться

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

8
ответ дан 4 December 2019 в 05:52
поделиться

Вы также можете ознакомиться с Glib / GObject , которые предоставляют механизм классов для языка C. Он используется во многих проектах, достаточно мощный и тщательно протестированный.

6
ответ дан 4 December 2019 в 05:52
поделиться

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

Помните, что операционные системы, GUI и другие управляемые событиями непроцедурные системы были написаны на C задолго до Появились Objective C и C ++. C - это не Cobol.

Перед изучением C ++ я написал управляемый событиями графический интерфейс на языке C, используя массивы указателей на функции. Инкапсуляция была простой, я не делал попыток полиморфизма, некоторые отношения полагались на стандарты кодирования и соглашения об именах, поскольку пространства имен и объекты были недоступны. Он включал настоящий синтаксический анализатор, рекурсивный, поскольку я еще не изучал класс Compiler в Uni. И да, все это умещается в 640 КБ, но я использовал наложения.

Некоторые люди пытаются создать псевдообъекты, используя указатели на функции в Structs. Я не вижу в этом смысла. В какой-то момент вы должны принять тот факт, что вы »

6
ответ дан 4 December 2019 в 05:52
поделиться

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

Взгляните на glib , gtk и gts для хороших примеров стиля кодирования ООП в C.

6
ответ дан 4 December 2019 в 05:52
поделиться

Вы получили много предложений о том, как реализовать объектно-ориентированные концепции на C, но если проблемная область не делает ООП очень желательным (например, программирование с графическим интерфейсом), вам следует использовать ИМО вместо C и других процедурные языки процедурным способом. ООП по своей природе не лучше для всех сценариев.

Возможно, вы захотите взглянуть на "старый добрый" метод структурированного анализа для фазы анализа / проектирования вашего проекта.

4
ответ дан 4 December 2019 в 05:52
поделиться

Продолжайте мыслить категориями классов и интерфейсов, предоставляемых классами. Класс C ++ будет отображаться в структуру C. Функции-члены класса становятся обычными функциями C. Предоставьте заголовок, объявляющий внешний интерфейс для «класса». Примите тот факт, что некоторые части C ++ недоступны в C - пространства имен, исключения (и, конечно же, классы).

2
ответ дан 4 December 2019 в 05:52
поделиться

Абсолютно ничего не мешает вам от использования тех же техник, которые вы используете в C ++, на C. Объектно-ориентированный дизайн, включая множественное наследование, достаточно просто реализовать. Вы даже можете выполнить программирование шаблонов, проявив небольшую смекалку с макросами. Единственное, что полученная программа на C не будет такой элегантной, как эквивалентный C ++, потому что язык не очень помогает вам с этими концепциями.

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

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

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

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

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

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

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

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

3
ответ дан 4 December 2019 в 05:52
поделиться

В языке C программисты часто имитируют идею класса, разделяя связанные функции в .h / .c файлы и рассматривать их как класс. Размещение переменных в локальной области видимости можно рассматривать как «частное».

2
ответ дан 4 December 2019 в 05:52
поделиться

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

1
ответ дан 4 December 2019 в 05:52
поделиться

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

2
ответ дан 4 December 2019 в 05:52
поделиться

Вот как можно получить одиночное наследование:

struct Base {
 int a;
};    
struct MyStruct {
  Base parent;
  int b;
};

struct MyStruct myStruct;
struct Base *base = (struct Base *) &myStruct;
printf("%d\n", base->a);
aFunctionExpectingBase(base);

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

0
ответ дан 4 December 2019 в 05:52
поделиться

Что ж, вы все еще можете создавать красивые абстрактные типы данных на C. Вы начинаете с typedef создания структуры, предоставляя функции создания / уничтожения, а затем другие методы установки / получения / исполнители для работы с этой структурой:

typedef struct {
  /* maintain private state here */
  unsigned int x;
  char *y;

} mytype_t;

/** Creates a new mytype... */
mytype_t *mytype_create(unsigned int x, char *y);

/** Destroys a mytype, freeing all associated memory. */
void mytype_destroy(mytype_t *t);

/** Does something to mytype... */
void mytype_do_something(mytype_t *t, int bla);

Таким образом, вы реализуете эти функции и поддерживаете свое состояние, обращаясь к «закрытым» членам в структуре, указатель которых передается каждой функции.

Затем вы могли бы использовать этот интерфейс следующим образом. :

mytype_t* t = mytype_create(foo, bar);
mytype_do_something(t);

/* do some other stuff */

mytype_destroy(t);

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

Я вижу, что люди типизируют структуры, чтобы избежать необходимости набирать 'struct' повсюду, но вы должны думать об этом как об определении нового абстрактного тип, внутренняя реализация которого может измениться. Конечно, пользователь этого типа может нырнуть и получить доступ к участникам, но это плохой поступок. Структура typedef означает «закрытый, держись подальше!». Это скрытие основной информации.

Я также склонен использовать префиксный стиль именования, например mytype_verb . Это помогает с intellisense, потому что я могу набрать mytype_ и получить список функций для этого типа. Это также помогает с конфликтами имен, поскольку в C нет поддержки пространства имен, поэтому вы увидите, что большинство библиотек C используют префиксы (например, sqlite3_ ) перед всем, что они определяют.

mytype_verb . Это помогает с intellisense, потому что я могу набрать mytype_ и получить список функций для этого типа. Это также помогает с конфликтами имен, поскольку в C нет поддержки пространства имен, поэтому вы увидите, что большинство библиотек C используют префиксы (например, sqlite3_ ) перед всем, что они определяют.

mytype_verb . Это помогает с intellisense, потому что я могу набрать mytype_ и получить список функций для этого типа. Это также помогает с конфликтами имен, поскольку в C нет поддержки пространства имен, поэтому вы увидите, что большинство библиотек C используют префиксы (например, sqlite3_ ) перед всем, что они определяют.

1
ответ дан 4 December 2019 в 05:52
поделиться

Используйте Функциональное разложение .

Функциональная декомпозиция - это метод сверху вниз для систематического проектирования программы. Идея состоит в том, чтобы разбить проблему на подзадачи, по очереди разбивая подзадачи, пока детали не станут достаточно точными, чтобы их можно было перевести на язык программирования. Разработчик должен выбрать, как устранить проблему.

0
ответ дан 4 December 2019 в 05:52
поделиться