Прочитайте SICP та вивчіть схему та практичну ідею абстрактних типів даних . Тоді кодування в C легко (оскільки при SICP, трохи C, трохи PHP, Ruby тощо) ваше мислення буде досить розширеним, і ви зрозумієте, що об'єктно-орієнтоване програмування може бути не найкращим стилем у всі випадки, але лише для якихось програм). Будьте уважні до динамічного розподілу пам’яті C , що, мабуть, найважча частина. Стандарт мов програмування C99 або C11 та його стандартна бібліотека С насправді досить бідні (він не знає про TCP або каталоги!), І вам часто знадобляться деякі зовнішні бібліотеки або інтерфейси (наприклад,POSIX , libcurl для клієнтської бібліотеки HTTP, libonion для бібліотеки серверів HTTP, GMPlib для bignums, деяка бібліотека, як libunistring для UTF-8 тощо).
Ваші "об'єкти" часто знаходяться в C деяких споріднених struct
, і ви визначаєте набір функцій, що діють на них. Для коротких або дуже простих функцій розгляньте їх визначення відповідною struct
, як static inline
у деяких файлах заголовка, foo.h
щоб бути #include
-d в іншому місці.
Зауважте, що об'єктно-орієнтоване програмування - не єдина парадигма програмування . В деяких випадках варті й інші парадигми ( функціональне програмування à la Ocaml, Haskell або навіть Scheme або Commmon Lisp, логічне програмування à la Prolog, і т.д. тощо ... Читайте також блог Дж. Пітрата про декларативний штучний інтелект). Дивіться книгу Скотта: Прагматика мови програмування
Власне, програміст на C або в Ocaml зазвичай не хоче кодувати в об'єктно-орієнтованому стилі програмування. Немає причин змушувати себе думати про предмети, коли це не корисно.
Ви визначите деякі struct
та функції, що працюють на них (часто через покажчики). Можливо, вам знадобляться кілька позначених об'єднань (часто, struct
з членом тегу, часто - деякими enum
, а хтось - union
всередині), і вам може бути корисним мати гнучкий член масиву в кінці деяких ваших struct
.
Загляньте в вихідний код деякого наявного вільного програмного забезпечення на C (див. Github & sourceforge,
щоб знайти його). Можливо, встановлення та використання дистрибутива Linux було б корисним: він створений майже лише з вільного програмного забезпечення, у ньому є чудові безкоштовні компілятори програмного забезпечення C ( GCC , Clang / LLVM ) та засоби розробки. Дивіться також Розширене програмування Linux, якщо ви хочете розвиватися для Linux.
Не забудьте скласти всі попередження та інформацію про налагодження, наприклад - gcc -Wall -Wextra -g
особливо під час етапів розробки та налагодження - та навчитися користуватися деякими інструментами, наприклад, valgrind для полювання на витоки пам'яті , gdb
налагоджувач тощо. Слідкуйте за тим, щоб добре зрозуміти, що не визначено поведінки і рішуче уникайте цього (пам’ятайте, що програма може мати певний UB і іноді, здається, «працює»).
Коли вам справді потрібні об'єктно-орієнтовані конструкції (зокрема спадкування ), ви можете використовувати вказівники на споріднені структури та функції. Ви можете мати власну vtable машину , кожен "об'єкт" починається з вказівника на покажчики, що struct
містять функції. Ви використовуєте можливість передачі типу вказівника іншому типу вказівника (і того, що ви можете передавати з struct super_st
містять ті ж типи полів, що і ті, що починають struct sub_st
з емуляції спадкування). Зауважте, що C достатньо для реалізації досить складних об'єктних систем, зокрема, дотримуючись деяких конвенцій, - як демонструє GObject (від GTK / Gnome).
Коли ви дійсно потрібні затвори , ви часто емулювати їх зворотні виклики , з конвенцією , що кожна функція зворотного виклику з використанням передаються як покажчик на функцію і деякі дані клієнта (споживаний покажчик на функції , коли вона називає це). Ви також можете мати (умовно) свої власні закриття struct
-s (містять деякий покажчик функції та закриті значення).
Оскільки мова є дуже низьким рівнем мови, важливо визначити та задокументувати власні конвенції (натхненні практикою в інших програмах C), зокрема про управління пам'яттю, і, напевно, також деякі умови іменування. Корисно мати деяке уявлення про архітектуру набору інструкцій . Не забувайте , що C компілятор може зробити багато оптимізацій на свій код (якщо ви попросите його), так що не все одно занадто багато про виконання мікро-оптимізацій вручну, відпустка , що ваш компілятор ( для оптимізації компіляції випущений програмне забезпечення). Якщо ви дбаєте про тестування показників та ефективність роботи, слід активувати оптимізацію (після налагодження програми).gcc -Wall -O2
Не забувайте, що інколи корисне метапрограмування . Досить часто велике програмне забезпечення, написане на C, містить деякі сценарії або спеціальні програми для створення деякого коду С, який використовується в іншому місці (і ви також можете грати деякі брудні хитрощі C-препроцесора , наприклад, X-макроси ). Існує кілька корисних генераторів програм C (наприклад, yacc або gnu bison для генерації парсерів, gperf для створення ідеальних хеш-функцій тощо). У деяких системах (зокрема Linux і POSIX) ви навіть можете генерувати якийсь код C під час виконання generated-001.c
файлу, компілювати його до спільного об'єкта, виконуючи якусь команду (наприклад gcc -O -Wall -shared -fPIC generated-001.c -o generated-001.so
) під час виконання, динамічно завантажувати спільний об'єкт за допомогою dlopen& отримати покажчик функції від імені за допомогою dlsym . Я роблю такі хитрощі в MELT (мова, схожа на Lisp, що може бути корисною для вас, оскільки вона дозволяє налаштувати компілятор GCC ).
Будьте в курсі концепцій та методів збору сміття ( підрахунок посилань часто є технікою управління пам’яттю в С, і це IMHO погана форма збору сміття, яка не справляється з круговими посиланнями ; у вас можуть бути слабкі вказівки, щоб допомогти у цьому, але це може бути хитро). В деяких випадках ви можете подумати про використання консервативного сміттєзбірника Бома .
qux = foo.bar(baz)
стаєqux = Foo_bar(foo, baz)
.