Чи є якась причина використовувати C замість C ++ для вбудованої розробки?


82

Питання

У мене є два компілятори на моєму обладнанні C ++ та C89

Я думаю про використання C ++ з класами, але без поліморфізму (щоб уникнути vtables). Основними причинами, якими я хотів би користуватися C ++, є:

  • Я вважаю за краще використовувати “вбудовані” функції замість визначень макросів.
  • Я хотів би використовувати простори імен, оскільки префікси захаращують код.
  • Я бачу C ++ трохи безпечнішим, головним чином завдяки шаблонам та багатослівному кастингу.
  • Мені дуже подобаються перевантажені функції та конструктори (використовуються для автоматичного кастингу).

Чи бачите ви будь-яку причину дотримуватися C89 при розробці для дуже обмеженого обладнання (4 кб оперативної пам'яті)?

Висновок

Дякую за відповіді, вони були дуже корисні!

Я продумав цю тему і дотримуватимусь C головним чином тому, що:

  1. Простіше передбачити фактичний код на мові C, і це дійсно важливо, якщо у вас є лише 4 кб оперативної пам'яті.
  2. Моя команда складається в основному з розробників C, тому розширені функції C ++ не будуть часто використовуватися.
  3. Я знайшов спосіб вбудованих функцій у своєму компіляторі C (C89).

Важко прийняти одну відповідь, оскільки ви дали стільки хороших відповідей. На жаль, я не можу створити вікі та прийняти її, тому я оберу одну відповідь, яка змусила мене думати найбільше.


11
Одне: завжди чітко розумійте, на якій мові ви пишете. Не намагайтеся писати програму на "C / C ++". Пишіть на мові C або пишіть на мові C ++, знаючи, якими функціями мови ви будете користуватися, а якими ні.
Девід Торнлі,


Визначте «вбудований розвиток»
Марко ван де Воорт,

@DavidThornley, ти цілком можеш мати рацію щодо вбудованих кейсів, але я був дуже приємно здивований тим, як гарно змішаний код C & C ++ грає разом, де я прагну розширити загальнодоступні програми з відкритим кодом, такі як Kamailio, зі STL. Я офіційно заохочую таке використання кодів STL та C, оскільки він пропонує надзвичайну функціональність та простоту обслуговування в майбутньому, створюючи майже нульові проблеми (відсутність вбудованих структур в C ++ є жахливим злочином проти C ++, і його слід якомога швидше виправити. ).
user2548100

Їжа для роздумів, ось чудова стаття, де дизайнер і автор ZeroMQ обговорює, чому він шкодує, що написав основу коду на C ++, а не на C. Не те, що я взагалі очікував, і з причин, не знайдених ніде на цій сторінці. 250bpm.com/blog:4
user2548100

Відповіді:


48

Дві причини використання C над C ++:

  1. Для багатьох вбудованих процесорів або немає компілятора C ++, або за це доведеться доплатити.
  2. Мій досвід полягає в тому, що значна частина вбудованих програмних інженерів мало або взагалі не має досвіду роботи з C ++ - або через (1), або через те, що вона, як правило, не викладається на електронних інженерних ступенях - і тому було б краще дотримуватися що вони знають.

Крім того, в оригінальному запитанні та ряді коментарів згадується 4 Кб оперативної пам'яті . Для типового вбудованого процесора обсяг оперативної пам’яті (в основному) не пов’язаний із розміром коду, оскільки код зберігається та запускається з флеш-пам'яті.

Безумовно, слід пам’ятати про кількість місця для зберігання коду, але, оскільки на ринку з’являються нові, більш місткі процесори, це стає менше проблемою, ніж раніше для всіх, крім найбільш економічно важливих проектів.

Щодо використання підмножини C ++ для використання із вбудованими системами: зараз існує стандарт MISRA C ++ , який, можливо, варто подивитися.

EDIT: Див. Також це запитання , яке призвело до суперечки про C проти C ++ для вбудованих систем.


2
Дивіться мою довшу відповідь нижче: C ++ дуже ускладнює розміщення постійних даних у FLASH.
jakobengblom2

3
Потенційно вагомою причиною використовувати C замість C ++ є стандартний ABI C. Просто для повноти.
Кріс Луц

66

Для цілі з дуже обмеженими ресурсами, такої як 4 КБ оперативної пам'яті, я б протестував води за допомогою деяких зразків, перш ніж докласти багато зусиль, які неможливо легко перенести назад у чисту реалізацію ANSI C.

Робоча група Embedded C ++ запропонувала стандартну підмножину мови та стандартну підмножину стандартної бібліотеки. На жаль, я загубив ці зусилля, коли журнал користувача C помер, на жаль. Схоже, у Вікіпедії є стаття , і що комітет все ще існує.

У вбудованому середовищі ви дійсно повинні бути обережними щодо розподілу пам’яті. Щоб забезпечити цю турботу, можливо, вам доведеться визначити глобального operator new()та його друзів до чогось, що навіть не може бути пов'язане, щоб ви знали, що воно не використовується. Розміщення, newз іншого боку, швидше за все, буде вашим другом, якщо його використовувати розумно разом зі стабільною схемою розподілу, гарантованою затримкою та затримкою.

Вбудовані функції не спричинять особливих проблем, якщо вони не настільки великі, що спочатку мали бути справжніми функціями. Звичайно, у макросів, які вони замінювали, була та сама проблема.

Шаблони теж можуть не створювати проблем, якщо їх екземпляр не запуститься. Для будь-якого шаблону, який ви використовуєте, перевіряйте згенерований код (на карті посилань може бути достатньо підказок), щоб переконатися, що відбулися лише ті екземпляри, які ви збиралися використовувати.

Ще одна проблема, яка може виникнути, - це сумісність з вашим налагоджувачем. Незвично, що апаратний налагоджувач, який можна використовувати інакше, має дуже обмежену підтримку взаємодії з вихідним вихідним кодом. Якщо вам ефективно потрібно налагоджувати в збірці, то цікаве назви керування C ++ може внести додаткову плутанину в завдання.

RTTI, динамічні трансляції, множинне успадкування, важкий поліморфізм та винятки - все це пов’язано з певною вартістю виконання для їх використання. Деякі з цих функцій рівні, які коштують за всю програму, якщо вони використовуються, інші просто збільшують вагу класів, які в них потребують. Дізнайтеся різницю та мудро вибирайте розширені функції з повним знанням хоча б побіжного аналізу витрат / вигод.

У невеликому вбудованому середовищі ви будете або безпосередньо підключатись до ядра реального часу, або працювати безпосередньо на апаратному забезпеченні. У будь-якому випадку вам потрібно буде переконатися, що ваш код запуску під час виконання правильно обробляє завдання запуску, що відповідають C ++. Це може бути настільки просто, як переконатися у використанні правильних параметрів компонувальника, але оскільки загальноприйнятим є прямий контроль над джерелом до точки входу при перезавантаженні, можливо, вам доведеться перевірити це, щоб переконатися, що він робить все. Наприклад, на платформі ColdFire, над якою я працював, інструменти розробника постачалися з модулем CRT0.S, який мав ініціалізатори С ++, але коментував їх. Якби я використовував його прямо з коробки, мене б спантеличили глобальні об'єкти, конструктори яких взагалі ніколи не працювали.

Крім того, у вбудованому середовищі часто потрібно ініціалізувати апаратні пристрої, перш ніж їх можна буде використовувати, а якщо немає ОС та завантажувача, то це робить ваш код. Вам потрібно буде пам’ятати, що конструктори для глобальних об’єктів запускаються до main() виклику, тому вам потрібно буде змінити локальний CRT0.S (або його еквівалент), щоб виконати таку ініціалізацію обладнання до виклику самих глобальних конструкторів. Очевидно, що вершина main()занадто пізня.


1
Цьому потрібно більше голосів, ніж я можу йому дати! ВЕЛИКА відповідь.
Харпер Шелбі,

+1, чудова відповідь. Але я вважаю, що єдиною інстанцією шаблону, про яку вам дійсно потрібно турбуватися, є (відносно рідкісний) рекурсивний тип - для "звичайного" нерекурсивного виду інстанціація становить код, який ви б і так набрали вручну.
j_random_hacker 02

2
@j_random_hacker, правда. Але звичка до шаблонів може призводити до випадкових сюрпризів, коли з’являється другий (або третій) екземпляр, коли примус належного типу на етапі використання міг йому завадити. Це просто щось, на що слід стежити.
RBerteig

@RBerteig: Хороший момент, шаблони дозволяють меншу кількість можливостей примусу типу => можливо, створюється більше чітких екземплярів, ніж із кодом без шаблону.
j_random_hacker

26

Ні. Будь-якої з функцій мови С ++, яка може спричинити проблеми (поліморфізм середовища виконання, RTTI тощо), можна уникнути, виконуючи вбудовану розробку. Існує спільнота вбудованих розробників C ++ (я пам’ятаю, як читала стовпці вбудованих розробників, що використовують C ++, у старому Журналі користувачів C / C ++), і я не можу уявити, що вони були б дуже голосистими, якби вибір був таким поганим.


20

Технічний звіт про продуктивність C ++ є відмінним орієнтиром для такого роду речі. Зверніть увагу, що в ньому є розділ, присвячений проблемам вбудованого програмування!

Крім того, ++ про згадку про Embedded C ++ у відповідях. Стандарт не на 100% на мій смак, але він є хорошим посиланням при виборі, які частини C ++ ви можете відмовитись.

Програмуючи для невеликих платформ, ми відключаємо винятки та RTTI, уникаємо віртуального успадкування та приділяємо пильну увагу кількості віртуальних функцій, які ми маємо.

Однак ваш друг - це карта зв’язку: перевіряйте її часто, і ви швидко помітите джерела коду та статичної пам’яті.

Після цього застосовуються стандартні міркування щодо використання динамічної пам'яті. Іноді ви можете уникнути пулів пам'яті для невеликих динамічних розподілів або розподілу на основі кадру, де ви попередньо виділите блок і викинете все це пізніше.


16

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

Ви можете продовжувати використовувати класи C ++ тощо, просто

  • Обмежте використання віртуальних функцій (як ви вже сказали)
  • Обмежте використання шаблонів
  • Для вбудованої платформи потрібно замінити оператор new та / або використовувати розташування new для розподілу пам'яті.

8
Звичайно, якщо ви вже в основному пишете C, ви можете також зробити це офіційним.
Чак

6
Чому ви обмежуєте використання шаблонів? Я думав, що функції шаблону можуть бути дуже корисними у вбудованих системах, наприклад, для розгортання циклів.
Piotr Czapla

1
Ви все ще можете використовувати шаблони, але я буду з ними дуже обережний, оскільки вони можуть швидко збільшити розмір вихідного двійкового файлу. Звичайно, якщо ваш код працює безпосередньо з ПЗУ або подібного, і у вас є вільний простір для ПЗУ, то, звичайно, але крім цього, ви повинні бути обережними з тим, що ви робите з шаблонами (кожен екземпляр шаблону в основному весь дублюється код шаблону у остаточному виконуваному файлі в гіршому випадку).
Арке

14

Як інженер вбудованого програмного забезпечення / вбудованої системи, я можу сказати вам, хлопці, деякі причини, чому C все ще є вибором №1 серед C ++, і так, я вільно володію ними обома.

1) Деякі цілі, на яких ми розробляємо, мають 64 КБ оперативної пам'яті як для коду, так і для даних, тому ви повинні переконатися, що кожен байт підраховується, і так, я мав справу з оптимізацією коду, щоб заощадити 4 байти, які коштують мені 2 години, і це в 2008 рік.

2) Кожна функція бібліотеки C перевіряється перед тим, як ми вводимо їх до остаточного коду, через обмеження розміру, тому ми віддаємо перевагу людям не використовувати розділення (відсутність апаратного дільника, тому потрібна велика бібліотека), malloc (оскільки у нас немає купи , вся пам'ять виділяється з буфера даних у 512-байтовий фрагмент і повинна бути переглянута кодом), або інша об'єктно-орієнтована практика, яка несе великі штрафи. Пам'ятайте, кожна функція бібліотеки, яку ви використовуєте, враховується.

3) Ви коли-небудь чули про термін накладання? у вас так мало місця в коді, що іноді доводиться міняти речі іншим набором коду. Якщо ви викликаєте функцію бібліотеки, тоді функція бібліотеки повинна бути резидентною. Якщо ви використовуєте його лише у функції накладання, ви витрачаєте багато місця, покладаючись на занадто багато об'єктно-орієнтованих методів. Отже, не приймайте жодної функції бібліотеки C, не кажучи вже про прийняття C ++.

4) Трансляція та навіть упаковка (там, де незрівнянна структура даних перетинає межу слова) необхідні через обмежену апаратну конструкцію (тобто механізм ECC, який підключений певним чином) або для вирішення апаратної помилки. Ви не можете припустити занадто багато явного, то чому об’єкт занадто орієнтує його?

5) Найгірший сценарій: усунення деяких об’єктно-орієнтованих методів змусить розробку задуматися, перш ніж вони використають ресурси, які можуть вибухнути (тобто виділити 512 байт у стеці, а не з буфера даних), і запобігти деяким з потенційно найгірших сценаріїв, що не тестуються і не усувають весь шлях коду разом.

6) Ми використовуємо багато абстракцій, щоб захистити обладнання від програмного забезпечення та зробити код максимально портативним та зручним для моделювання. Доступ до апаратного забезпечення повинен бути обгорнутий у макрос або вбудовану функцію, умовно скомпільовану між різними платформами; тип даних повинен бути відлитий як розмір байтів, а не конкретний цільовий, використання прямого вказівника не дозволяється (оскільки деякі платформи вважають, що введення / вивід, що відображає пам'ять, є те саме, що пам'ять даних) тощо.

Я можу придумати більше, але ти розумієш. У нас, хлопці, прошивки, є об’єктно-орієнтоване навчання, але завдання вбудованої системи може бути настільки апаратно орієнтованим і низьким рівнем, що воно не є високим рівнем або відступним від природи.

До речі, кожна робота в прошивці, в якій я був, використовує контроль джерел, я не знаю, звідки ви берете цю ідею.

- якийсь хлопець із прошивки від SanDisk.


ще на початку 90-х накладання було дуже популярною технікою (принаймні у світі DOS)
психоделія

Хороші бали Шинг. C ++ відчуває себе борцем сумо в телефонній будці в проектах, де функціональність обмежена, а ресурси ще більш обмежені.

4
Я вважаю, що ця відповідь дуже суб'єктивна і не дає конкретних міркувань.
Венемо

1
С ++ не обов'язково означає "об'єктно-орієнтований".
Мартін Боннер підтримує Моніку

1
Це просто неправда, що завдання вбудованої системи за своєю суттю не є абстракційними. Ви самі сказали це в пункті 6): "ми використовуємо багато абстракцій, щоб утримати hw від sw і зробити код якомога переноснішим" :-) ДО: BTW: "абстракція" не обов'язково означає "поліморфізм".
Даніеле Палластреллі,

9

Моя особиста перевага - C, оскільки:

  • Я знаю, що робить кожен рядок коду (і коштує)
  • Я недостатньо добре знаю C ++, щоб знати, що робить кожен рядок коду (і коштує)

Чому люди так говорять? Ви не знаєте, що робить кожен рядок C, якщо не перевірити вихід asm. Те саме стосується і C ++.

Наприклад, що asm створює це невинне твердження:

a[i] = b[j] * c[k];

Це виглядає досить невинно, але компілятор, заснований на gcc, створює цей asm для 8-бітного мікро

CLRF 0x1f, ACCESS
RLCF 0xfdb, W, ACCESS
ANDLW 0xfe
RLCF 0x1f, F, ACCESS
MOVWF 0x1e, ACCESS
MOVLW 0xf9
MOVF 0xfdb, W, ACCESS
ADDWF 0x1e, W, ACCESS
MOVWF 0xfe9, ACCESS
MOVLW 0xfa
MOVF 0xfdb, W, ACCESS
ADDWFC 0x1f, W, ACCESS
MOVWF 0xfea, ACCESS
MOVFF 0xfee, 0x1c
NOP
MOVFF 0xfef, 0x1d
NOP
MOVLW 0x1
CLRF 0x1b, ACCESS
RLCF 0xfdb, W, ACCESS
ANDLW 0xfe
RLCF 0x1b, F, ACCESS
MOVWF 0x1a, ACCESS
MOVLW 0xfb
MOVF 0xfdb, W, ACCESS
ADDWF 0x1a, W, ACCESS
MOVWF 0xfe9, ACCESS
MOVLW 0xfc
MOVF 0xfdb, W, ACCESS
ADDWFC 0x1b, W, ACCESS
MOVWF 0xfea, ACCESS
MOVFF 0xfee, 0x18
NOP
MOVFF 0xfef, 0x19
NOP
MOVFF 0x18, 0x8
NOP
MOVFF 0x19, 0x9
NOP
MOVFF 0x1c, 0xd
NOP
MOVFF 0x1d, 0xe
NOP
CALL 0x2142, 0
NOP
MOVFF 0x6, 0x16
NOP
MOVFF 0x7, 0x17
NOP
CLRF 0x15, ACCESS
RLCF 0xfdf, W, ACCESS
ANDLW 0xfe
RLCF 0x15, F, ACCESS
MOVWF 0x14, ACCESS
MOVLW 0xfd
MOVF 0xfdb, W, ACCESS
ADDWF 0x14, W, ACCESS
MOVWF 0xfe9, ACCESS
MOVLW 0xfe
MOVF 0xfdb, W, ACCESS
ADDWFC 0x15, W, ACCESS
MOVWF 0xfea, ACCESS
MOVFF 0x16, 0xfee
NOP
MOVFF 0x17, 0xfed
NOP

Кількість вироблених інструкцій суттєво залежить від:

  • Розміри a, b і c.
  • незалежно від того, зберігаються ці вказівники у стеку або є глобальними
  • незалежно від того, чи є i, j та k в стеку, чи є глобальними

Це особливо вірно у крихітному вбудованому світі, де процесори просто не налаштовані на обробку C. Тому моя відповідь буде такою, що C і C ++ такі ж погані, як один одного, якщо ви не завжди перевіряєте вихід asm, і в цьому випадку вони такі ж добрі, як один одного.

Гюго


2
Зауважте також, що посередині всього, що насправді викликає функцію множення, є інструкція виклику. Весь цей код навіть не є інструкцією множення!
Rocketmagnet

Хтось, хто знайомий з мікро, зазвичай знає простий спосіб опрацювати кожну частину коду С ізольовано, і гідний компілятор не повинен створювати код, який гірший за це. Єдиний спосіб наведеного вище виразу може бути ефективно оброблений, якщо зробити припущення, які можуть не відповідати компілятору C.
supercat

8

Я чув, що деякі люди віддають перевагу C для вбудованої роботи через те, що він простіший і, отже, простіше передбачити фактичний код, який буде створений.

Я особисто вважаю, що написання C ++ у стилі C (із використанням шаблонів для безпеки типу) дасть вам масу переваг, і я не бачу жодної реальної причини, щоб цього не робити.


+1, прозорість завжди важлива, і, можливо, більше для обмеженого середовища з (імовірно) обмеженими інструментами налагодження.
j_random_hacker

7

Я не бачу жодної причини використовувати C замість C ++. Що б ви не могли зробити на C, ви можете зробити це також на C ++. Якщо ви хочете уникнути накладних витрат на VMT, не використовуйте віртуальні методи та поліморфізм.

Однак C ++ може надати дуже корисні ідіоми без накладних витрат. Один з моїх улюблених - RAII. Заняття не є дорогими з точки зору пам'яті або продуктивності ...


6

Я написав певний код для вбудованої в ARM7 форми пальми на IAR Workbench. Я настійно рекомендую покладатися на шаблони для оптимізації часу компіляції та прогнозування шляху. Уникайте динамічного лиття, як чуми. Використовуйте риси / політики на свою користь, як це передбачено в книзі Андрія Александреску « Сучасний дизайн на C ++» .

Я знаю, це може бути важко навчитися, але я також впевнений, що ваш підхід виграє від цього підходу.


5

Вагома причина, а іноді і єдина причина полягає в тому, що досі немає компілятора C ++ для конкретної вбудованої системи. Це стосується, наприклад, мікроконтролерів Microchip PIC . Для них дуже легко писати, і вони мають безкоштовний компілятор C (насправді, невеликий варіант C), але компілятора C ++ не видно.


1
Comeau Computing ( comeaucomputing.com ) продає компілятор C ++, який компілює до C.
Thomas L Holaday,

3
Ой. Цей сайт викликав бажання повернути.
shoosh

@shoosh: Так, дизайн сайту жахливий. Однак сам компілятор вважається лідером у цій галузі, принаймні з точки зору стандартної відповідності (я не маю інформації про продуктивність).
j_random_hacker

Цей веб-сайт змушує мене відчувати, що я потрапив у пастку живого, дихаючого та ДУЖЕ сердитого фруктового салату.
Тім Пост

5

Для системи, обмеженої 4K оперативної пам'яті, я б використовував C, а не C ++, лише для того, щоб ви могли бути впевнені, що бачите все, що відбувається. Річ у C ++ полягає в тому, що дуже просто використовувати набагато більше ресурсів (як процесора, так і пам’яті), ніж це виглядає, як кинути погляд на код. (О, я просто створу ще один BlerfObject, щоб зробити це ... ой! З пам'яті!)

Ви можете зробити це в C ++, як уже згадувалося (без RTTI, без vtables тощо тощо), але ви витратите стільки часу, щоб переконатися, що ваше використання C ++ не відходить від вас, як це було б зроблено в еквіваленті .


2
Ваше останнє речення правильне, але неактуальне, оскільки С ++ пропонує інші переваги перед С, які (можуть) схилити баланс. Пьотр уже згадував деякі з цих (нульових) переваг.
Конрад Рудольф

5

Людський розум має справу зі складністю, оцінюючи якомога більше, а потім вирішуючи, на чому важливо зосередитися, а відкидаючи або знецінюючи решту. Це вся підстава для брендингу в маркетингу, і значною мірою, ікон.

Для боротьби з цією тенденцією я віддаю перевагу C замість C ++, оскільки це змушує вас думати про свій код і про те, як він тісніше взаємодіє з обладнанням - невблаганно тісно.

На моєму багаторічному досвіді, я вважаю, що C змушує вас придумувати кращі рішення проблем, частково, збиваючись з дороги і не змушуючи витрачати багато часу на задоволення обмежень, які деякі компілятори-автори вважали хорошою ідеєю. , або з’ясувати, що відбувається «під ковдрою».

Таким чином, мови низького рівня, такі як C, ви витрачаєте багато часу на апаратне забезпечення та створення хороших наборів структури даних / алгоритмів, тоді як на мовах високого рівня ви проводите багато часу, чухаючи голову, дивуючись, що там відбувається , і чому ви не можете зробити щось цілком розумне у вашому конкретному контексті та середовищі. Побиття компілятора для подання (сильний набір тексту - найгірший порушник) - це НЕ продуктивне використання часу.

Я, мабуть, добре підганяю форму для програміста - мені подобається контроль. На мій погляд, це не є вадою особистості програміста. Контроль - це те, за що нам платять. Більш конкретно, БЕЗГРЕШНИЙ контроль. C дає вам набагато більше контролю, ніж C ++.


Мартін Сістрік, автор ZeroMQ, майже те саме зазначив у своєму обговоренні, чому він хотів би, щоб він зараз писав ZeroMQ на мові C, а не на C ++. Перевірте 250bpm.com/blog:8
user2548100

3

Особисто, маючи 4 кб пам’яті, я б сказав, що ви не отримуєте набагато більше пробігу від C ++, тому просто виберіть той, який здається найкращим поєднанням компілятора / часу роботи, оскільки мова, ймовірно, не буде мати великого значення.

Зауважте, що мова також йде не про мову, оскільки також має значення бібліотека. Часто бібліотеки C мають трохи менший мінімальний розмір, але я міг уявити, що бібліотека C ++, орієнтована на вбудовану розробку, вирізана, тому обов'язково протестуйте.


2

C виграє у переносимості - оскільки він менш неоднозначний у специфікації мови; отже, пропонуючи набагато кращу портативність та гнучкість для різних компіляторів тощо (менше головних болів).

Якщо ви не збираєтеся використовувати функції C ++ для задоволення потреби, перейдіть до C.


Чи буде мова однозначною, залежить від того, чи можна вважати її специфікою речей, які раніше вважалися здоровим глуздом, але в наш час не [наприклад, що компілятор для 32-розрядного мовчазного обгортання двох комплектуючих апаратних засобів повинен обробляти щось на зразок unsigned mul(unsigned short x, unsigned short y) { return x*y;}відсутності побічні ефекти, навіть якщо продукт перевищує 2147483647, або що це повинно розглядати void get_float_bits(float *fp, uint32_t n) { *(uint32_t)fp = n; }як можливе зміна значення а float].
суперкіт

2

Чи бачите ви будь-яку причину дотримуватися C89 при розробці для дуже обмеженого обладнання (4 кб оперативної пам'яті)?

Особисто, коли мова заходить про вбудовані програми (коли я кажу про вбудовані, я не маю на увазі winCE, iPhone тощо. Сьогодні роздуті вбудовані пристрої). Я маю на увазі обмежені ресурси. Я віддаю перевагу C, хоча я теж працював із C ++.

Наприклад, пристрій, про який ви говорите, має 4 кб оперативної пам'яті, ну якраз з цієї причини я б не розглядав C ++. Звичайно, ви можете спроектувати щось невелике за допомогою C ++ та обмежити використання цього у своїй програмі, як пропонують інші публікації, але C ++ "може" потенційно може ускладнити / роздути вашу програму під ковдрами.

Збираєтесь статично посилатися? Можливо, ви захочете порівняти статичну фіктивну програму за допомогою c ++ та c. Це може змусити вас розглянути замість C. З іншого боку, якщо ви можете створити програму C ++ відповідно до ваших потреб у пам’яті, переходьте до цього.

ІМХО, загалом, у вбудованих програмах я люблю знати все, що відбувається. Хто використовує пам’ять / системні ресурси, скільки і чому? Коли вони звільняють їх?

При розробці для цілі з X обсягом ресурсів, процесором, пам’яттю тощо. Я намагаюся залишатись на нижчій стороні використання цих ресурсів, тому що ви ніколи не знаєте, які майбутні вимоги з’являться, таким чином, додаючи до проекту більше коду, який "мав бути" простим невеликим додатком, але в підсумку стає набагато більшим.


1
Я обов’язково порівняю два компілятори. (До речі. Я не можу динамічно пов'язувати, оскільки немає операційної системи)
Piotr Czapla

2

Мій вибір, як правило, визначається бібліотекою C, яку ми вирішили використовувати, яка вибирається на основі того, що потрібно зробити пристрою. Отже, 9/10 разів .. в кінцевому підсумку це uclibc або newlib і C. Ядро, яке ми використовуємо, також має великий вплив на це, або якщо ми пишемо власне ядро.

Це також вибір точки дотику. Більшість хороших програмістів на С не мають проблем із використанням С ++ (хоча багато хто весь час скаржиться, що вони ним користуються) .. але я не знайшов зворотного, що відповідає дійсності (на моєму досвіді).

У проекті, над яким ми працюємо (який включає занулене ядро), більшість речей робиться на мові С, однак невеликий мережевий стек був реалізований на мові С ++, оскільки було просто простіше і менш проблематично реалізувати мережу за допомогою С ++.

Кінцевим результатом є те, що пристрій буде працювати або проходити приймальні випробування, або ні. Якщо ви можете реалізувати foo у xx стеку та обмеження кучі yy, використовуючи мову z, перейдіть до цього, використовуйте те, що робить вас більш продуктивними.

Моя особиста перевага - C, оскільки:

  • Я знаю, що робить кожен рядок коду (і коштує)
  • Я недостатньо добре знаю C ++, щоб знати, що робить кожен рядок коду (і коштує)

Так, мені зручно користуватися C ++, але я його не знаю так добре, як стандартний C.

Тепер, якщо ви можете сказати зворотне, добре, використовуйте те, що ви знаєте :) Якщо це спрацьовує, проходить тести тощо. В чому проблема?


2
> # Я знаю, що робить кожен рядок коду (і коштує). Написавши компілятори, я не був би впевнений у цьому ... хороший компілятор C може зробити для вашого коду досить дивовижні речі, оскільки він має хороший глобальний огляд речі. Він не компілює послідовно.
jakobengblom2

@ jakobengblom2: Для вбудованої розробки стабільність продуктивності часто важливіша за максимальну продуктивність. Якщо хтось намагається визначити, чи відповідає шматок коду тимчасовим вимогам, якщо компілятор застосує оптимізації, які можуть бути використані в "тестовій" прошивці, яка не буде працювати в реальній прошивці, це може бути менш корисно.
supercat

2

Скільки у вас ROM / FLASH?

4 кБ оперативної пам'яті все ще може означати, що є сотні кілобайт FLASH для зберігання фактичного коду та статичних даних. Оперативна пам'ять такого розміру, як правило, призначена лише для змінних, і якщо ви будете обережні з цими, ви можете помістити в пам'ять досить велику програму з точки зору кодових рядків.

Однак C ++ має тенденцію ускладнювати розміщення коду та даних у FLASH через правила побудови об'єктів під час виконання. У C константна структура може бути легко поміщена в пам'ять FLASH і доступна як апаратно-константний об'єкт. У C ++ постійний об'єкт вимагав би від компілятора оцінки конструктора під час компіляції, що, на мою думку, все ще перевищує можливості компілятора C ++ (теоретично ви могли б це зробити, але це дуже важко зробити на практиці) .

Отже, в середовищі "маленької оперативної пам'яті", "великої флеш-пам'яті" я б ходив із С будь-якого дня. Зауважте, що хорошим проміжним вибором є C99, який має більшість приємних функцій C ++ для коду, що не базується на класах.


3
Чи є якась причина, чому та сама структура, яка була б поміщена у флеш-пам’ять на C, також не потрапила б у Flash на C ++? Вам не потрібно додавати конструктор до своєї структури в C ++.
jalf

1

Загалом ні. С ++ - це набір С. Це особливо актуально для нових проектів.

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

Зауважте, що деякі речі, такі як поліморфізм, можуть бути дуже цінними - це, по суті, вказівники на функції. Якщо ви виявите, що вони вам потрібні, використовуйте їх - з розумом.

Крім того, хороша (добре розроблена) обробка винятків може зробити вашу вбудовану програму надійнішою, ніж програма, яка обробляє речі з традиційними кодами помилок.


2
С ++, строго кажучи, не є суворою надмножиною С, але ця конкретна деталь не особливо суттєва в цьому контексті.
Арафангіон,

1

Що стосується проблеми розподілу пам'яті, я можу рекомендувати використовувати Quantum Platform та її підхід до стану машини, оскільки вона виділяє все, що вам потрібно на час ініціалізації. Це також допомагає полегшити проблеми із суперечками.

Цей продукт працює як на C, так і на C ++.


1

Деякі кажуть, що компілятори C можуть генерувати набагато ефективніший код, оскільки їм не потрібно підтримувати розширені функції C ++, і тому вони можуть бути більш агресивними в своїх оптимізаціях.

Звичайно, у цьому випадку ви можете перевірити два конкретні компілятори.


1
Пов’язане: Ключове слово restrict - це, наскільки я знаю, єдина конструкція C, пов’язана з оптимізацією, відсутня в C ++ (також C ++ 11).
Йоган Лундберг

1

Єдина причина віддати перевагу C IMHO полягала б у тому, що компілятор C ++ для вашої платформи не у належній формі (помилка, погана оптимізація тощо).


А як щодо використання пам'яті / ресурсів?
Стів Лазарідіс,

Що з цим? Немає причин для компілятора С ++ створювати менш ефективний код, ніж код С, за винятком випадків, коли код використовує RTTI, чого ніхто не робить у вбудованих системах.
Неманья Трифунович


1

Ви вбудовані в C99. Можливо, вам подобаються ctors, але справа з виправленням dtors може бути безладною. Якщо єдиною причиною не використовувати C є простори імен, я б дійсно дотримувався C89. Це тому, що вам може знадобитися перенести його на дещо іншу вбудовану платформу. Пізніше ви можете почати писати на C ++ за цим самим кодом. Але пам’ятайте наступне, де C ++ - НЕ надмірна частина C. Я знаю, ви сказали, що у вас є компілятор C89, але все одно робить це порівняння C ++ із C99, оскільки перший пункт, наприклад, справедливий для будь-якого C, починаючи з K&R.

sizeof 'a' > 1 в C, а не в C ++. У C у вас є масиви змінної довжини VLA. Приклад: func (int i) {int a [i] . У C у вас є члени масиву змінних VAM. Приклад: struct {int b; int m [];} .


1
Ні. Я маю на увазі згадати, що в C у вас є (sizeof 'a') == sizeof (int). У той час як у C ++ у вас є 1 == sizeof 'a'
hept

1
Не кажучи вже про "int * a; ...; a = (int *) malloc (size * sizeof (int));" це спосіб виділення пам'яті, яка працює на C і C ++, і не повинна використовуватися ні в одному, ні в іншому. Використовуйте або "a = malloc (size * sizeof (int));" або "vector <int> a (size);" або навіть "int * a = new int [size];" натомість.
Девід Торнлі,

1
Я не розумію вашої думки щодо dtors. Вся суть у них полягає в тому, що вони роблять решту вашого коду набагато меншою .
jalf 02

1
+1, не впевнений, чому ця публікація отримала такий поганий реп. Але я погоджуюсь з jalf, деструктори сильно спрощують код, коли використовуються правильний (RAII) спосіб. (Можна сказати, що вони "працюють за лаштунками", але вони роблять лише те, що в будь-якому випадку правильний код буде робити вручну.)
j_random_hacker

1
Я думаю, що речі, на які я вказую, дуже відповідають цьому питанню. Я також дотримуюся свого твердження, що dtors може бути важким, і причина саме в тому, що це відбувається автоматично. Я отримав мінус бали - це справді гач. Думаю, це тому, що я не кажу "ТАК, ПЕРЕЙТИ C ++ це ВЕЛИКО".
hept

1

Це залежить від компілятора.

Не всі вбудовані компілятори реалізовують весь C ++, і навіть якщо вони це роблять, вони, можливо, не вміють уникати роздуття коду (що завжди є ризиком для шаблонів). Перевірте його за допомогою декількох менших програм, переконайтеся, що у вас не виникли проблеми.

Але, маючи хороший компілятор, ні, немає жодної причини не використовувати С ++.


1

Просто хочу сказати, що не існує системи з "НЕОБМІЖЕНИМИ" ресурсами. У цьому світі все обмежено, і КОЖНА програма повинна враховувати використання ресурсів незалежно від того, є це ASM, C, JAVA чи JavaScript. Манекени, які виділяють кілька Мб, "щоб бути впевненим", роблять iPhone 7, Pixel та інші пристрої надзвичайно вибагливими. Незалежно від того, маєте ви 4 кб або 40 Гб.

Але з іншого боку виступити проти витрачання ресурсів - це час, який потрібен для економії цих ресурсів. Якщо потрібно 1 тиждень додатково, щоб написати просту річ на мові C, щоб зберегти кілька галочок і кілька байтів замість того, щоб використовувати вже впроваджений, протестований та розподілений C ++. Навіщо турбуватись? Це як придбання USB-концентратора. так, ви можете зробити це самостійно, але чи буде це краще? надійніше? дешевше, якщо рахувати свій час?

Лише побічна думка - навіть потужність від вашої торгової точки не безмежна. Спробуйте дослідити, звідки воно береться, і ви побачите, в основному, це від спалення чогось. Закон енергії та матеріалу все ще діє: жоден матеріал чи енергія не з'являється або не зникає, а навпаки, перетворюється.


0

Я щойно знайшов приклад, як використовувати ISO C ++ для вбудованої розробки, що може бути цікавим для когось, хто приймає рішення при використанні C ++ або C.

Її надав Бьярн Страуструп на своїй домашній сторінці :

Погляд на те, як ISO C ++ може бути використаний для серйозного програмування вбудованих систем, див . У стандартах кодування JSF на повітряному транспорті C ++ .


Ну, літаючі речі, як правило, мають процесори PPC з гігабайтами оперативної пам'яті. Не ваша середня вбудована система з обмеженими ресурсами.
jakobengblom2

0

Різні відповіді на різні аспекти питання:

"malloc"

Деякі попередні відповіді досить багато говорять про це. Чому ти взагалі думаєш, що цей дзвінок існує? Для справді невеликої платформи malloc, як правило, недоступний або, безумовно, необов’язковий. Реалізація динамічного розподілу пам’яті, як правило, має сенс, коли у вас є RTOS в нижній частині вашої системи, але до того часу це суто небезпечно.

Без цього можна дуже далеко зайти. Подумайте лише про всі старі програми FORTRAN, які навіть не мали належного стеку для локальних змінних ...


0

Існує ціла низка різних виробників контролерів по всьому світу, і коли ви заглянете в їх конструкції та набори інструкцій, які потрібно використовувати для налаштування, у вас можуть виникнути численні проблеми. Основним недоліком асемблерної мови є залежність машини / архітектури. Насправді величезно попросити розробника напам'ять усі інструкції, викладені там, для виконання кодування для різних контролерів. Ось чому C став більш популярним у вбудованій розробці, оскільки C достатньо високий, щоб абстрагувати алгоритми та структури даних від апаратно-залежних деталей, роблячи вихідний код портативним для широкого спектра цільового обладнання, незалежної від архітектури мовою та дуже легким для конвертувати та підтримувати код. Але ми бачимо деякі мови високого рівня (об'єктно-орієнтовані), такі як C, C ++, Python, Java тощо.


0

Я рекомендую С ++ з обмеженнями та примітками.

  1. Час виходу на ринок та ремонтопридатність. Розробка С ++ простіша і швидша. Отже, якщо ви перебуваєте на етапі проектування, виберіть контролер, достатньо підходящий для використання C ++. (Зверніть увагу, що деякі великі ринки вимагають якомога менших витрат, якщо ви не можете зробити такий вибір.)

  2. Швидкість. C може бути швидшим, ніж C ++, але переконайтеся, що це збільшення швидкості не є великим. Тож ви можете піти з C ++. Розробіть свої алгоритми, протестуйте їх і зробіть їх швидшими лише за потреби (!). Використовуйте профайлери, щоб вказати вузькі місця і переписати їх зовнішнім знаком "С" , щоб досягти швидкості С. (Якщо все-таки повільно впровадити цю частину в ASM)

  3. Бінарний розмір. Кодів C ++ більше, але ось чудова відповідь, яка розповідає подробиці. Розмір скомпільованого двійкового файлу даного коду С буде однаковим, незалежно від того, чи був він скомпільований за допомогою компілятора С або С ++. "Розмір виконуваного файлу навряд чи пов'язаний з мовою, а з бібліотеками, які ви включаєте у свій проект." Перехід з C ++ , але уникнути додаткових функцій, як streams, string, new, virtualфункція і т.д. Огляд всіх функцій бібліотеки , перш ніж дозволити їм в кінцевому коді, з - за обмеження розміру (на підставі цього відповіді)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.