Стів Саміт
Лінь - двигун прогресу! - Експериментуйте полегшуючи собі життя!
Стів Саміт. Мова си у питаннях та відповідях.ANSI C.
Відповіді на запитання розбиті на теми:
ANSI C5.1 Що таке стандарт ANSI C?
5.2 Як отримати копію Стандарту?
5.3 Чи є у когось утиліти для перекладу С-програм, написаних у старому стилі, в ANSI C і навпаки? Чи існують програми для автоматичного створення прототипів?
5.4 Я намагаюся використовувати ANSI-рядкоутворюючий оператор #, щоб вставити у повідомлення значення символічної константи, але вставляється формальний параметр макросу, а не його значення.
В: Необхідно використовувати двокрокову процедуру для того, щоб макрос розкривався як при рядкоутворенні Така процедура встановлює opname рівним «plus», а не «OP». Такі самі обхідні маневри необхідні за умови використання оператора склеювання лексем ##, коли потрібно з'єднати значення (а чи не імена формальних параметрів) двох макросів. Дивись: ANSI Розд. 3.8.3.2, Розд. 3.8.3.5 приклад с. 93.
5.5 Не розумію, чому не можна використовувати незмінні значення при ініціалізації змінних та завданні розмірів масивів, як у наступному прикладі:
const int n = 5; int a[n];
Відповідь: Кваліфікатор const означає «тільки для читання». Будь-який об'єкт кваліфікований як const, є нормальним об'єктом, що існує під час виконання програми, якому не можна привласнити інше значення. Отже, значення такого об'єкта — це константне вираження в повному розумінні цього слова. (У цьому сенсі С не схожий наС++). Якщо є потреба у справжніх константах, що працюють під час компіляції, використовуйте препроцесорну директиву #define. Дивись: ANSI Розд. 3.4.
5.6 Яка різниця між "char const *p" і "char * const p"?
В: "char const *p" - це покажчик на постійну літеру (її не можна змінити); "char * const p" - це незмінний покажчик на змінну (її можна змінювати) типу char. Зарубайте це собі на носі. також 10.4. Дивись: ANSI Розд. 3.5.4.1.
5.7 Чому не можна передати char** функції, що очікує const char**?
5.8 Мій ANSI компілятор відзначає розбіжність, коли зустрічається з деклараціямиextern int func(float);int func(x) float x;
5.9 Чи можна змішувати визначення функцій у старому та новому стилі?
Відповідь: Змішування стилів є абсолютно законним, якщо дотримується обережності (зверніть особливу увагу на питання 5.8). Зауважте, однак, що визначення функцій у старому стилі вважається таким, що виходить із вживання, і одного разу підтримка старого стилю може бути припинена.
5.11 У мене виникають дивні повідомлення про помилки всередині коду, «вимкненого» за допомогою #ifdef.
5.12 Чи можу я оголосити main як void, щоб припинилися дратівливі повідомлення «main return no value»? (Я викликаю exit(), так що main нічого не повертає).
О ні. main повинна бути оголошена як повертає int і використовує або два або жодного аргументу (відповідного типу). Якщо використовується exit(), але попереджувальні повідомлення не зникають, Вам потрібно буде вставити зайвий return, або використовувати, якщо це можливо, директиви на кшталт notreached. Оголошення функції як void просто не впливає на попередження компілятора; крім того, це може породитиіншу послідовність виклику/повернення, несумісну з тим, що очікує функція, що викликає, (у разі main це виконуюча система мови С). Дивись: ANSI Розд. 2.1.2.2.1 с. 7-8.
5.13: Чи еквівалентне повернення статусу за допомогою exit(status) поверненню за допомогою return?
В: Формально, так, хоча невідповідності виникають у деяких старих нестандартних системах, у тих випадках, коли дані, локальні для main(), можуть знадобитися в процесі завершення виконання (можливо при викликах setbuf() або atexit()), або при рекурсивний виклик main(). Дивись: ANSI Розд. 2.1.2.2.3 с. 8.
5.14 Чому стандарт ANSI гарантує лише шість значущих символів (за відсутності відмінності між великими та малими символами) для зовнішніх ідентифікаторів?
5.15 Яка різниця між memcpy та memmove?
Відповідь: memmove гарантує правильність операції копіювання, якщо дві області пам'яті перекриваються. memcpy не дає такої гарантії і, отже, може бути ефективніше реалізована. У разі сумнівів краще застосовувати мемові. Дивись: ANSI Розд. 4.11.2.1, 4.11.2.2, Rationale Розд.4.11.2.
5.16 Мій компілятор не транслює найпростіші тестові програми, надаючи всілякі повідомлення про помилки.
Відповідь: Ваш компілятор розроблений до прийому стандарту ANSI і тому не здатний обробляти прототипи функцій тощо. також питання 5.17 та 17.2.
5.17 Чому не визначено деякі підпрограми зі стандартної ANSI-бібліотеки, хоча у мене ANSI сумісний компілятор?
Відповідь: Немає нічого незвичайного в тому, що компілятор, який сприймає ANSI синтаксис, не має ANSI-сумісних головних файлів або стандартних бібліотек. також питання 5.16 та 17.2.
5.18 Чомукомпілятор "Frobozz Magic C", про який говориться, що він ANSI-сумісний, не транслює мою програму? Я знаю, що текст підпорядковується стандарту ANSI, тому що він транслюється компілятором gcc.
Відповідь: Практично всі компілятори (а gcc — більше) підтримують деякі нестандартні розширення. Чи ви впевнені, що відкинутий текст не застосовує одне з таких розширень? Небезпечно експериментувати з компілятором для вивчення мови. Стандарт може допускати відхилення, а компілятор працювати неправильно. також питання 4.4.
5.19 Чому мені не вдаються арифметичні операції з покажчиком типу void *?
Відповідь: Тому що компілятору не відомий розмір об'єкта, на який вказує void*. Перед арифметичними операціями використовуйте оператор приведення до типу (char*) або типу, з яким збираєтеся працювати. (Дивіться, однак, питання 2.18).
5.20 Чи правильний запис a[3]=»abc»? Що це означає?
В: Цей запис вірний в ANSI C (і, можливо, в деяких ранніх компіляторах), хоча корисність такого запису є сумнівною. Оголошується масив розміру три, що ініціалізується трьома літерами 'a','b',і 'c' без завершального символу стринг '\0'; Отже, масив не може використовуватися як стрінг функціями strcpy, printf %s і т.п. Дивись: ANSI Розд. 3.5.7 с. 72-3.
5.21 Що таке #pragma і де це може стати в нагоді?
5.22 Що означає #pragma once? Я знайшов цю директиву в одному з головних файлів.
В: Це розширення, реалізоване деяких препроцессорах, робить головний файл ідемпотентним, тобто. ефект від одноразового включення файла дорівнює ефекту багаторазового включення. Ця директива призводить до того ж результату, як і прийом з використанням #ifndef, описаний у питанні 6.4.
5.23 Начебто існує різниця між залежною від реалізації, неописаною (unspecified) і невизначеною (undefined) поведінкою. У чому ця різниця?
Якщо говорити коротко, то при залежній від реалізації поведінці необхідно вибрати один варіант і документувати його. При неописаному поведінці також вибирається одне із варіантів, але у разі немає необхідності це документувати. Невизначена поведінка означає, що може статися що завгодно. У жодному з цих випадків Стандарт не висуває вимог; у перших двох випадках Стандарт іноді пропонує (а може й вимагати) вибір із кількох близьких варіантів поведінки. Якщо Ви зацікавлені в написанні мобільних програм, можете ігнорувати різницю між цими трьома випадками, оскільки їх необхідно уникати. Дивись: ANSI Розд.1.6, особливо «Rationale».