Чи потрібно слідувати стандарту, взяти для цього стандарт С?


17

На Stack Overflow є дуже досвідчені люди, які завжди говорять про стандарт C. Люди, здається, не люблять портативні рішення, навіть якщо вони працюють на мене. Гаразд, я розумію, що стандарту потрібно дотримуватися, але чи це не ставить кайдани на творчість програміста?

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


7
Чи можете ви пояснити, що ви маєте на увазі під «стандартом»? Ви маєте на увазі не реалізацію поведінки, яка не визначена стандартом? Або не використовуєте розширення / функції компілятора? Або умовні стилі?
ikh

1
@ikh Він дотримується стандартів ISO C (C90, C99, C11).
Aseem Bansal

9
Це те саме, що говорити, що писати чи говорити англійською мовою, використовуючи англійську граматику та словниковий запас, ставить кайдани на вашу творчість. Звичайно, люди можуть робити чудові речі, порушуючи правила, ціною узгодженості, але ви можете написати мільйони креативних книг, досі дотримуючись "стандарту" англійської мови.
Авнер Шахар-Каштан

чи можете ви додати приклад "Люди, здається, не люблять портативні рішення, навіть якщо вони працюють на мене"?
BЈовић

1
@PHIfounder Просто для вирішення цього останнього випадку ви можете опустити повернення з основного, це неявно повернути 0 :)
Daniel Gratzer

Відповіді:


45

Є кілька причин, чому дотримання стандарту - це добре.

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

  2. Замикаючись на платформі, смокче важче. Якщо ви натискаєте програмне забезпечення на Linux і хочете перейти на Windows, оскільки ви розумієте, що ваш ринок дійсно є, вам доведеться чекати час, змінюючи кожен не портативний хак, який у вас є в коді, щоб грати добре як з GCC, так і з MSVC. Якщо у вас є кілька частин вашого основного дизайну на основі чогось подібного, удачі!

  3. Зміни, несумісні ззаду, відсмоктують найважче. Стандарт ніколи не порушить ваш код (Ignore python). Деякі випадкові автори компілятора, можливо, вирішать, що справді це доповнення для конкретної реалізації не варте клопоту, і скинути його. Якщо ви випадково покладаєтесь на це, то ви зациклюєтесь на будь-якій старій застарілій версії, в якій вона була останньою.

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

  • Бібліотеки
  • Підтримка (люди знають стандарт, а не кожен складний хакер-компілятор)
  • Доступні платформи
  • Зрілі інструменти
  • Безпека (майбутні докази)

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


+1 достатньо справедливо :), дякую ... Мені було серйозно заплутано те, як компілятори трохи відхилилися від стандартів і змусили мене скептично ставитися до того, щоб чітко дотримуватися його, потрібно знати плюси та мінуси цього, і ви їх чітко визначили.
0decimal0

6
Невизначена поведінка, мабуть, також засмоктує. З c досить легко вступати в UB, якщо ви не дотримуєтесь стандарту уважно.
CodesInChaos

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

6

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

Отже, яка перевага дотримуватися стандартної, а не власної ментальної моделі?

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

Люди, здається, не люблять портативні рішення, навіть якщо вони працюють на мене.

Можливо, краще сказати, "навіть якщо вони, здається, працюють на мене". Якщо ваш компілятор спеціально не документує, що дана поведінка буде працювати (тобто якщо ви не використовуєте збагачений стандарт, що складається з належної стандартної плюс документації компілятора), ви не знаєте, що це дійсно працює або що це справді надійно. Наприклад, підписане ціле число переповнення, як правило, призводить до завершення роботи в багатьох системах (так, INT_MAX+1як правило, INT_MIN) - за винятком того, що компілятори "знають", що підписана ціла арифметика ніколи не переливається в (правильну) програму C, і часто проводять дуже дивні оптимізації на основі цього " знання ».


1
Ви можете компілювати -fwrapv, а потім використовуєте трохи іншу, нестандартну мову, де підписана ціла арифметика завжди обгортається.
користувач253751

@immibis: Коли C89 був написаний, згідно з його документом обгрунтування, більшість сучасних укладачів визначили тиху обертову семантику для цілого переповнення. У багатьох випадках наявність певних гарантій щодо того, що станеться у випадку цілого переповнення, може дозволити коду бути ефективнішим, ніж це було б можливо без таких гарантій, особливо якщо гарантії не заходять так далеко, щоб надати точну поведінку для завершення [точно поведінку загортання можна імітувати за допомогою непідписаної математики, але семантика, яка більш пухка, але все ще достатня для задоволення вимог, може дозволити більш ефективний код].
supercat

@immibis: Дуже погано, що ревізіоністи змогли переконати людей у ​​тому, що поведінка, реалізована майже одноголосно серед компіляторів для певних платформ (або в деяких випадках 100% одноголосно), ніколи не була «стандартною» на таких платформах, оскільки в багатьох випадках втрата ефективності, що виникає внаслідок уникнення такої поведінки, не буде компенсована жодними "оптимізаціями", яких компілятор зміг досягти, скасувавши їх.
supercat

4

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

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


Оскільки ви згадали конкретний приклад void main()vs int main(), я можу вдосконалити свою відповідь.

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

З іншого боку, стандарт чітко визначає підпис основного як int main()і вказує, що він повинен робити.


З іншого боку, є речі, які не визначені у стандарті. Потім може застосовуватися інший стандарт (наприклад, POSIX). Найкращим прикладом може бути реалізація потоків у c ++ 03, оскільки стандартні програми c ++ 03 були 1-потоковими. У такому випадку ви змушені використовувати залежну від платформи бібліотеку, або щось на кшталт boost .


4
Все, що робить компілятор, що не є стандартним, не є невизначеною поведінкою, розширення компілятора чітко визначені в тому сенсі, що вони детерміновані і навмисні. UB - ні.
Даніель Грацер

@jozefg Як його запитали - очевидно, що ОП думала про спосіб реалізації UB. Наприклад, потоки не були визначені в c ++ 03.
BЈовић

1
@deworde: коментар видалено з відповіді.
Кевін

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

-6

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


2
без пояснення ця відповідь може стати марною у випадку, якщо хтось інший висловить протилежну думку. Наприклад, якщо хтось опублікував претензію на кшталт "дотримуйтесь правил, якщо ваш проект стосується спеціальних проектів, наприклад, проекту gov або армії, але вам не потрібно дотримуватися правил, якщо ви говорите про відкритий код ..." , як ця відповідь допоможе читачеві вибрати дві протилежні думки? Подумайте про те, щоб відредагувати його у кращій формі
gnat

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