Мобільне програмування в середовищі ОС UNIX

[ виправити ] текст може містити помилки, будь ласка перевіряйте перш ніж використовувати.

скачати

Зміст

Мобільне програмування в середовищі ОС UNIX

Стандартні бібліотеки

Бібліотека системних викликів

Бібліотека вводу / виводу

Додаткові бібліотеки

Файли заголовків

Мобільність на рівні вихідних текстів

Особливості мобільного програмування на мові Сі

Забезпечення незалежності від особливостей версії ОС UNIX

Бінарна сумісність

Можливості досягнення бінарної сумісності

Переваги та обмеження

Стандартні бібліотеки

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

Бібліотека системних викликів

Базовою бібліотекою будь-якого варіанту системи UNIX є бібліотека системних викликів. Зараз неможливо знайти два варіанти ОС UNIX з різними назвами, набори системних викликів яких повністю б співпадали. Однак, будь-який такий варіант підтримує системні виклики, які специфіковані в стандартах, що згадуються в розділі 7.5. До повністю стандартним системним викликам відносяться системні виклики для роботи з файлами (включаючи спеціальні файли), системні виклики для управління процесами (fork і сімейство exec), системні виклики класу IPC (хоча, як ми згадували в п. 3.5.4, в UNIX System V механізм програмних каналів реалізований не у вигляді набору системних викликів ядра ОС, а як набір бібліотечних функцій над пакетом TLI). Наведене в дужках зауваження насправді є дуже важливим. Користувача, який прагне створити мобільну програму з використанням системних викликів, не повинні хвилювати деталі реалізації. Важливо, щоб склад системних викликів, їх інтерфейси і семантика відповідали стандартам.

Тепер ми можемо сформулювати правило прикладного мобільного програмування з використанням системних викликів:

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

Дотримуючись цього правила, з великою ймовірністю ви не будете мати проблем з перенесенням програми у середу іншого варіанту ОС UNIX через несумісність наборів системних викликів.

Бібліотека вводу / виводу

Традиційною для ОС UNIX бібліотекою функцій більш високого рівня, ніж бібліотека системних викликів, є, так звана, стандартна бібліотека вводу / виводу (stdio). Основний набір функцій цієї бібліотеки служить для виконання файлових операцій з буферизацією даних у пам'яті користувача процесу. Бібліотека вводу / виводу фактично стандартизована дуже давно, і їй можна безпечно користуватися в будь-якій операційній середовищі. Зокрема, однакові бібліотеки вводу / виводу підтримуються у всіх сучасних реалізаціях системи програмування мови Сі, виконаних не в середовищі ОС UNIX (включаючи реалізації в середовищі MS-DOS).

Тому можна сформулювати правило мобільного програмування з використанням бібліотеки введення / виводу:

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

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

Додаткові бібліотеки

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

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

Тому можна сформулювати правило мобільного програмування з використанням додаткових бібліотек:

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

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

Файли заголовків

Використання текстових файлів заголовків (header-файлів), які вставляються в текст програми на мові Сі з допомогою директиви include препроцесора Сі, є традиційною технікою програмування на мові Сі в середовищі ОС UNIX, що забезпечує синтаксичну правильність використання бібліотечних функцій (в тому числі і системних викликів ) в прикладній програмі. Раніше файли заголовків, головним чином, містили визначення типів і символічних констант (символічні константи - це константи, яким зіставлені імена за допомогою директиви define препроцесора Сі), використовуваних в інтерфейсах відповідних бібліотечних функцій. Коректне застосування файлів заголовків дозволяло програмістам не піклуватися про правильність типів даних, використовуваних при зверненні до бібліотечних функцій і обробці їх результатів.

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

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

Подальший хід міркувань очевидний. Для групи споріднених бібліотечних функцій робиться загальний файл заголовків, що містить необхідні визначення типів даних і символічних констант, а також набір прототипів цих бібліотечних функцій. Після включення в файл компіляції такого файлу заголовків на стадії компіляції будуть виявлені всі синтаксичні помилки звернення до бібліотечних функцій. У попередньому параграфі ми відзначили, що це рішення не абсолютно. Це дійсно так, оскільки в принципі ніхто не може змусити програміста на мові Сі включати в текст програми всі необхідні файли заголовків. Однак, така специфіка світу програмування: кожен може ускладнювати своє життя в такій мірі, в якій йому або їй це подобається.

Останнє зауваження щодо файлів заголовків. Останнім часом вони містять велику кількість операторів умовної компіляції, що відносяться здебільшого до визначення символічних констант. Справа в тому, що залежно від версії операційної системи (ми маємо на увазі версії однієї лінії ОС UNIX, наприклад, UNIX System V) значення констант, використовуваних з одним і тим же змістом, часто змінюються. Звичайно, прикладна програма не повинна залежати від таких змін. Наявність операторів умовної компіляції всередині файлу заголовків вирішує цю проблему.

Тому останнє правило цього розділу можна сформулювати наступним чином:

При програмуванні на мові Сі з використанням бібліотечних функцій використовуйте всі необхідні файли заголовків. Це допоможе швидше знайти помилки і підвищить мобільність прикладної програми.

Мобільність на рівні вихідних текстів

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

Особливості мобільного програмування на мові Сі

Особлива роль мови програмування Сі полягає в тому, що він, з одного боку, дозволяє писати для UNIX-систем практично настільки ж ефективний код, що і мови асемблера, а з іншого, є основним засобом перенесення програм між UNIX-системами. Можна сказати, що Сі є машинно-незалежним мовою асемблера для UNIX-систем. Це робить його основним засобом написання ефективних і переносних програм для цього класу обчислювальних систем. Стандартизація мови спочатку Американським національним інститутом стандартів (ANSI), а потім і Міжнародною організацією по стандартах (ISO) закріпила цю роль, поширивши її й на персональні комп'ютери. Будемо посилатися на версію мови Сі, визначену стандартом, як на мову ANSI C.

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

Програма на ANSI C стерпна з вихідної ЗС у цільову, якщо вона успішно компілюється в цільової ВС і її робота функціонально еквівалентна роботі у вихідній НД

На переносимість програми впливають особливості як апаратного, так і програмного оточення мови у вихідній і до цільового НД Можна виділити чотири чинника, що впливають на переносимість програми:

архітектура обчислювальних систем; метричні обмеження компіляторів; алгоритми роботи компіляторів; особливості операційних систем.

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

Навіть якщо програма задовольняє всім обмеженням ANSI C і пройшла стадію компіляції у вихідній ЗС, може статися, що в цільової НД вона цю стадію не пройде через те, що деякі метричні характеристики програми не задовольняють обмеженням, прийнятим у цільової НД Прикладами таких характеристик є: число рівнів вкладеності складових операторів, операторів циклу та операторів вибору варіанта; число описувачів покажчика, масиву і функції, модифікуючих базовий тип в описі об'єкта; число виразів, вкладених один в одного за круглим дужках і т.п.

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

Нарешті, семантика багатьох стандартних бібліотечних функцій (наприклад, функцій вводу / виводу) залежить від особливостей операційної системи.

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

Неуточняемое поведінка (unspecified behavior) - це поведінка правильних програм з коректними даними в ситуаціях, для яких стандарт не висуває ніяких вимог.

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

Поведінка, обумовлений реалізацією (implementation-defined behavior) - поведінка правильно написаної програми з правильними даними, яке залежить від характеристик реалізації і яка повинна бути документовано кожною реалізацією.

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

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

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

Неуточняемое поведінку

Не уточнюються наступні питання:

Метод і час ініціації статичних даних.

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

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

Попередні чотири ситуації впливають на виведення тексту на дисплеї.

Представлення плаваючих типів.

Стерпна програма не повинна використовувати інформацію про подання (тобто про бітової структурі) плаваючих типів, оскільки саме в реалізації плаваючої арифметики істотно розрізняються різні обчислювальні системи.

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

За винятком тих випадків, коли порядок обчислення виразу зафіксований синтаксичними правилами або зазначено в стандарті яким-небудь іншим чином (для операції виклику функції (), операцій логічного множення, логічного складання, умовної операції та операції перерахування висловів), порядок обчислення подвираженія та порядок виникнення побічних ефектів не уточнюється. Вираз, що містить більше, ніж одне входження однієї і тієї ж комутативною і асоціативної бінарної операції (*, +, &, ^, |), може вільно перегруповуватися, незалежно від наявності дужок, за умови, що типи операндів або результати від такої перегрупування НЕ зміняться. У стерпної програмі слід уникати виразів, порядок обчислення яких істотно впливає на їхнє значення або виробляються побічні ефекти. Якщо ж такий вислів виникає, то містить його оператор завжди можна розбити на еквівалентну послідовність з декількох операторів, що не містять подібних виразів. Наприклад, оператор

x = f () + g ();

можна замінити на послідовність операторів

y = f ();

x = y + g ();

або

y = g ();

x = f () + y;

в залежності від потрібного порядку виклику функцій f () і g ().

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

Відведення пам'яті під формальні параметри.

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

Значення індикатора позиції файлу після успішного виконання функції ungetc для текстового потоку до тих пір, поки не будуть введені або знищені всі запомненние символи. Подробиці про значення, запам'ятовуємо у разі успішної роботи функції fgetpos. Подробиці про значення, що виробляється для текстового потоку у разі успішної роботи функції ftell. Порядок і взаємне розташування областей пам'яті, що захоплюються функціями calloc, malloc і realloc. Який з двох елементів, які опинилися рівними при порівнянні, повертається функцією bsearch. Порядок розстановки в відсортованому функцією qsort масиві двох елементів, які опинилися рівними при порівнянні. Структура календарного часу, що повертається функцією time.

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

Невизначена поведінка

Поведінка не визначається для таких ситуацій:

У вихідній програмі виявлений символ, що не входить в необхідний набір. Виняток робиться для препроцесорну лексем, символьних і рядкових констант, а також приміток. Робиться спроба модифіковані строкову константу. Ідентифікатори, які повинні позначати одну і ту ж сутність, розрізняються хоча б одним символом. У символьній або строковою константі виявлена ​​невідома керуюча послідовність. Лексично перший опис функції або об'єкта даних з зовнішньої зв'язком не має файлової області видимості, а наступне опис лексично ідентичного ідентифікатора має або внутрішню, або зовнішню комунікацію, що суперечить першому опису. Арифметичне перетворення дає результат, який не може бути представлений у відведеному просторі. Арифметична операція невірна (наприклад, ділення на 0) або видає результат, який не можна уявити у відведеному просторі (наприклад, переповнення або втрата значимості). Число фактичних параметрів виклику не узгоджується з числом формальних параметрів функції, яка не має чинного у цій області видимості прототипу. Типи фактичних параметрів виклику після розширення не узгоджуються з розширеними типами формальних параметрів функції, яка не має чинного у цій області видимості прототипу і не має прототипу, що діє в області видимості, відповідної області визначення функції. Прототип функції є в області видимості, відповідної області визначення функції, формальний параметр описаний з типом, який змінюється в результаті дії розширень типу, що проводяться за замовчуванням, а функція викликається, коли в області видимості немає семантично еквівалентного прототипу. Викликається функція, обробна змінне число параметрів, але прототип з еліптичною нотацією відсутній у даній області видимості. Викликається функція з прототипом, дивись в даній області, її формальний параметр описаний з типом, який змінюється в результаті дії розширень типу, що проводяться за замовчуванням, але в області визначення функції не видно семантично еквівалентного прототипу функції. Зустрілася невірне посилання на масив, посилання на порожній покажчик або посилання на об'єкт, розміщений в області автоматично розподіляє пам'яті завершився блоку. Покажчик на функцію перетвориться в покажчик на функцію іншого типу і використовується для виклику функції, тип якої відрізняється від початкового. Покажчик на об'єкт, який не є елементом масиву, використовується в операції додавання або віднімання константи. Обчислюється різниця покажчиків, що відносяться до різних масивів. Результат вираження зсувається на негативну величину або на величину, більшу або рівну (в бітах) розміром зрушуваної результату. Порівнюються покажчики, пов'язані з різним складовим об'єктах. Значення об'єкта присвоюється перекривній пам'яті об'єкту. Робиться спроба змінити об'єкт, описаний як константа, за допомогою покажчика на тип, в якому немає атрибуту const. Об'єкт, описаний з атрибутом volatile, вказується за допомогою покажчика на тип, який не має такого ж атрибуту. Описи об'єкта, який має зовнішню комунікацію, в двох різних файлах або в різних областях видимості одного файлу, дають цьому об'єкту різні типи. Значення автоматичного неініційоване об'єкта використовується до першого присвоєння. Використовується результат роботи функції, яка, однак, не повертає ніякого значення. Функція, обробна змінне число параметрів, визначається без списку типів параметрів у еліптичної нотації. Фактичний параметр макровизова не має жодної препроцесорну лексеми. Всередині списку параметрів макровизова є препроцесорну лексеми, які можуть бути проінтерпретовані як директиви препроцесора. В результаті виконання препроцесорну операції злиття лексем (# #) виходить невірна препроцесорна лексема. Ефект, що виникає в програмі при перевизначенні зарезервованого зовнішнього ідентифікатора. Параметр identifier в макровизове offset відповідає бітового поля запису. Фактичний параметр бібліотечної функції має невірне значення, якщо тільки поведінка цієї функції в подібному випадку не описано явно. Бібліотечна функція, обробна змінне число параметрів, не описана. Для доступу до цієї функції assert використана макродіректіва # undef. Фактичний параметр функції, обробній символи, виходить за область визначення. Виклик функції setjmp проводиться в іншому контексті, ніж при порівнянні з цілочисловим виразом з констант в перемикачі або в умовному операторі. Значення автоматичного об'єкта, що не має атрибута volatile, змінилося між викликами setjmp і longjmp. Функція longjmp викликається з динамічно вкладеної програми обробки сигналу. Сигнал виникає не в результаті роботи функцій abort або raise, а при обробці сигналу викликається бібліотечна функція, яка не є самою функцією signal, або зі статичним об'єктом проробляється НЕ присвоювання йому значення статичної змінної з атрибутом volatile типу sig_atomic_t. Параметр parmN макровизначеннями va_start описується в класі реєстрової пам'яті. При виклику макроімені va_arg чергового фактичного параметра не виявилося. Тип фактичного параметра зі списку параметрів не узгоджується з типом, зазначеним у макровизове va_arg. Функція va_end викликається без попереднього звернення до макровизову va_start. З функції зі змінним числом параметрів, список яких був проініціірован за допомогою макровизова va_start, повернення здійснюється до виклику va_end. Формат у функціях fprintf і fscanf не відповідає переліку фактичних параметрів. У форматі функцій fprintf або fscanf виявлена ​​невірна специфікація перетворення. Серед специфікатором перетворення для специфікації, що не входить до списку o, x, X, e, E, f, g і G зустрівся ознака #. Фактичним параметром функції fprintf, що не відповідає перетворенням% s та% p, є складовою об'єкт або покажчик на складової об'єкт. Окрему перетворення у функції fprintf породило більше 509 вихідних символів. Фактичним параметром перетворення% p функції fscanf є значення індексу, видане при перетворенні% p функцією fprintf під час попередніх запусків програми. Результат перетворення, виконуваного функцією fscanf, не може бути представлений в об'ємі пам'яті, відведеної для нього, або отриманий об'єкт має невідповідний тип. Результат перетворення рядка в число за допомогою функцій atof, atoi або atol не може бути представлений. Фактичний параметр функцій free або realloc не збігається з раніше отриманими покажчиками, виробленими функціями calloc, malloc або realloс, або вказується об'єкт, що раніше знищений викликом функцій free або realloc. Посилання на пам'ять, звільнену функціями free або realloc. При виклику з функції exit функція, зареєстрована зверненням до atexit, виробляє доступ до автоматичного об'єкту програми. Результат цілочисельних арифметичних функцій (abs, div, labs або ldiv) не може бути представлений. Масив, в який йде запис копіюванням або конкатенацією, занадто малий. Функції memcpy, strcpy або strncpy копіюють об'єкт в перекривається з ним по пам'яті інший об'єкт. У форматі функції strftime виявлена ​​невірна специфікація перетворення.

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

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

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

Поведінка, залежне від реалізації

Кожна реалізація повинна описати поведінку у всіх ситуаціях, перерахованих у цьому розділі.

Семантика фактичних параметрів функції main.

Для полегшення перенесення програми корисно локалізувати обробку зовнішніх аргументів.

Число значущих початкових символів (понад 31) в ідентифікаторі без зовнішнього зв'язку.

У стерпної програмі не використовується понад 31 значущого символу в ідентифікаторах без зовнішнього зв'язку.

Число значущих початкових символів (понад 6) у ідентифікаторі із зовнішнім зв'язком.

У стерпної програмі не використовується понад 6 значущих символів в ідентифікаторах з зовнішньої зв'язком.

Чи має значення регістр символів, що входять в ідентифікатори з зовнішньої зв'язком.

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

Символи вхідного алфавіту, крім явно визначених у стандарті.

Це стосується, в основному, символів, використовуваних в символьних і рядкових константах (наприклад, російські літери).

Символи з набору часу виконання (за винятком пустого символу і (в оточенні виконання) явно певних символів вхідного символьного набору) та їх коди.

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

Відповідність символів вхідного алфавіту (в символьних і рядкових константах) символів алфавіту часу виконання.

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

Число і порядок символів в цілому.

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

Число і порядок проходження розрядів в символах з набору символів часу виконання.

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

Переносної програмі не слід використовувати інформацію цих двох пунктів.

Значення символьної константи, що складається більш, ніж з одного символу.

У стерпної програмі не слід використовувати символьні константи більше, ніж з одного символу.

Чи слід трактувати "прості" символьні об'єкти як знакові або беззнакові.

Стерпна програма не повинна залежати від того, чи є тип char знаковим або беззнакові.

Представлення та набори значень різних цілочисельних типів.

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

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

Стерпна програма не використовує цю інформацію.

Результати порозрядних операцій над цілими.

У стерпної програмі слід використовувати тільки такі поразрядное операції, результат яких не залежить від реалізації.

Знак залишку цілочисельного ділення.

Стерпна програма не використовує цю інформацію.

Чи є зрушення вправо значення знакового цілочисельного типу логічним або арифметичним.

Стерпна програма не повинна залежати від виду зсуву вправо знакових цілих.

Представлення та набори значень різних типів дійсних чисел.

Стерпна програма не залежить від подання дійсних чисел. Набори значень речових типів впливають на точність обчислень.

Спосіб округлення, коли дійсне число перетвориться до більш вузького речовинним числа.

У стерпної програмі краще за все виходити з того, що спосіб округлення невідомий.

Тип цілого, яке може вмістити максимальний розмір масиву, тобто тип size_t - тип результату операції sizeof.

Результат перетворення покажчика в ціле і навпаки.

Тип цілого, яке може вмістити різниця між двома покажчиками на один і той же масив - ptrdiff_t.

Стерпна програма не повинна використовувати інформацію попередніх трьох пунктів.

Елемент суміші union використовується як елемент іншого типу.

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

Доповнення пустот і вирівнювання елементів записів.

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

Чи вважається "просте" ціле бітове поле знаковим або беззнакові.

Чи переходить бітове поле, не уміщається в одному цілому, у наступний.

Порядок розташування бітових полів в цілому.

Чи може бітове поле перетинати фізичні межі комірок пам'яті.

Стерпна програма не повинна використовувати всю цю інформацію.

Максимальне число описувачів, які можуть модифікувати базовий тип.

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

Максимальна кількість варіантів у перемикачі.

Стерпна програма повинна виходити з того, що кількість варіантів у перемикачі не повинно перевищувати 255.

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

Метод зв'язку з вхідними файлами, що підлягають включенню в програму.

Обробка імен в лапках, що відносяться до включаються файлів.

Поведінка кожної директиви # pragma.

Визначення імен __DATE__ і __TIME__, коли, відповідно дата і час трансляції не може бути доступно.

Константа, що виходить при підстановці макровизначеннями NULL, що позначає порожній покажчик.

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

Діагностичне повідомлення і спосіб завершення програми, застосовуваний у функції assert.

Набори символів, що перевіряються в функціях isalnum, isalpha, iscntrl, islower, isprint і isupper.

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

Встановлюють чи математичні функції цілий вираз errno в положення ERANGE при виникненні втрати значимості.

Набір сигналів для функції signal.

Семантика кожного сигналу, що розпізнається бібліотечної функцією signal.

Обробка замовчувань і входів в програму для кожного виду сигналів, які розпізнаються функцією signal.

Відновлюється чи стандартна обробка, якщо при обробці сигналу функцією, вказаній при виконанні функції signal, виникає сигнал SIGILL.

Чи потрібно закінчувати останній рядок текстового потоку символом "кінець рядка".

Чи з'являться при введенні звичайні прогалини, записані в текстовий потік безпосередньо перед символом кінця рядка тексту.

Кількість символів NULL, які дописують до двійкового потоку.

Характеристики буферизації файлів.

Чи існує файл нульової довжини.

Правила освіти правильних імен файлів.

Чи може один файл відкриватися багато разів.

Результат виконання функції remove над відкритим файлом.

Ефект роботи функції rename, якщо файл з новим ім'ям існував раніше.

Вихідна рядок, що виходить при роботі перетворення% p у функції fprintf.

Вхідна рядок, що надходить для перетворення% p у функції fscanf.

Інтерпретація символу ^, який є ні перший, ні останній символ в списку сканування в перетворенні% [у функції fscanf.

Значення, яке отримує errno від функцій fgetpos і ftell у випадку невдачі.

Повідомлення, що видаються функцією perror.

Поведінка функцій calloc, malloc і realloc у разі, якщо розмір запитаної пам'яті дорівнює нулю.

Поведінка функції abort по відношенню до відкритих і тимчасових файлів.

Статус, що повертається функцією exit, якщо значення фактичного параметра не дорівнює нулю, або значенням макроімена EXIT_SUCCESS і EXIT_FAILURE.

Набір імен оточення і метод зміни списку оточення, використовуваний функцією getenv.

Зміст і режим виконання командного рядка функцією system.

Знак значення, що повертається функцією порівняння (memcmp, strcmp або strncmp), якщо перша пара розрізняються символів різниться в старшому розряді.

Зміст рядків повідомлень про помилки, які повертаються функцією strerror.

Місцевий часовий пояс і літній час.

Точка відліку для функції clock.

Метричні обмеження стерпної програми

Стерпна програма повинна відповідати таким метричним обмеженням:

15 рівнів вкладеності складових операторів, операторів циклу та операторів вибору варіанта. 6 рівнів вкладеності умовної трансляції. 12 описувачів покажчика, масиву і функції, модифікуючих базовий тип в описі об'єкта. 127 виразів, вкладених один в одного за дужки. 31 значущий символ на початку ідентифікатора із внутрішнім зв'язком або імені макровизначеннями. 6 значущих символів на початку імен, які мають зовнішню комунікацію. 511 зовнішніх імен в одному вихідному файлі. 127 імен в одному блоці. 1024 імені макроозначень, одночасно діють в одному вихідному файлі. 31 параметр у виклику або визначенні функції. 31 параметр у макровизове або макроозначень з параметрами. 509 символів в одній логічної вихідної рядку. 509 символів в рядковій константі (після конкатенації). 32767 байтів для розміщення об'єкта. 8 рівнів вкладеності по включаються файлів. 255 міток вибору варіанта в перемикачах. Забезпечення незалежності від особливостей версії ОС UNIX

Специфічним видом мобільності додатків на рівні вихідних текстів є можливість їх виконання з кількома версіями одного і того ж варіанти ОС UNIX, включаючи ранні версії, далекі від сучасних стандартів. Досить часто пізні версії не забезпечують повної сумісності з більш ранніми версіями, оскільки така сумісність не дала б можливості добитися в пізніх версіях відповідності стандартам.

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

Бінарна сумісність

Якщо зазвичай досягнення мобільності прикладних програм є метою прикладних програмістів, то іноді досягнення бінарної сумісності при виконанні прикладних програм є завданням розробників операційних систем. Під бінарної сумісністю операційної системи О2 з операційною системою О1 розуміється можливість виконання в середовищі О2 без перекомпіляції (а, можливо, і без перекомпонування) додатків, написаних для виконання в середовищі О1. Природно, що бінарна сумісність двох операційних середовищ теоретично досяжна тільки в тому випадку, коли обидві операційні системи О1 і О2 базуються на деякій загальній апаратній платформі (реально, найчастіше доводиться чути про бінарної сумісності різних варіантів ОС UNIX, що працюють на платформах Intel).

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

Можливості досягнення бінарної сумісності

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

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

Переваги та обмеження

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

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


Додати в блог або на сайт

Цей текст може містити помилки.

Програмування, комп'ютери, інформатика і кібернетика | Реферат
84.6кб. | скачати


Схожі роботи:
Основи програмування в середовищі Delphi 7 0
Основи програмування в середовищі Delphi 70
Програмування на VBA в середовищі MS Excel
Основи програмування в середовищі Qbasic
Основні роботи операційної системи UNIX Підтримка мережі UNIX
Розробка програм у середовищі програмування Turbo Pascal 70
Рішення задач лінійного програмування в середовищі Maple
Розробка програм у середовищі програмування Turbo Pascal 7 0
Засоби виводу інформації на принтер в об єктно орієнтованому середовищі програмування Delphi
© Усі права захищені
написати до нас