Чому auto a = 1; компілювати в C?


125

Код:

int main(void)
{
    auto a=1;
    return 0;
}

збирається без помилок компілятором MS Visual Studio 2012, коли файл має розширення .c. Я завжди думав, що при використанні розширення .c компіляція повинна відповідати синтаксису C, а не C ++. Більше того, наскільки я знаю, авто без типу дозволено лише в C ++, оскільки C ++ 11, де це означає, що тип виводиться з ініціалізатора.

Чи означає це, що мій компілятор не дотримується C, або код справді правильний на мові С?


8
Або компіляція в режимі C ++ (можливий), або MS все ще застрягла в останньому тисячолітті. Імпліцит intбуло вилучено зі стандарту C у 1999 році.
Єнс Ґуведт

16
@JensGustedt MSVC ++ підтримує лише C89 (та кілька функцій від C99). Це більше компілятор C ++.
ntoskrnl

3
@Brandin: за допомогою параметра / Wall він попереджає C4431, кажучи, що специфікатор типу відсутній і що за замовчуванням int більше не підтримується в C (див. Коментар Йенса). Це трохи суперечність, оскільки, очевидно, цей компілятор підтримує це ...
lee77

4
@JensGustedt За цією мірою GCC 4.7, випущений у 2012 році (і пізніші версії, підозрюю - я не маю таких під рукою) також "застряг в останньому тисячолітті". Він компілює код ОП без навіть повідомлення, коли йому не подано жодних прапорів.

3
@delnan, я принаймні припускав, що ОП увімкнула рівні попередження. Я, очевидно, помилявся. І в певному сенсі це правда, gcc також все ще застряг там, оскільки вони як і раніше не мають C99 (або варіант) за замовчуванням. Кланг попереджає про конструкцію навіть без прапорців.
Jens Gustedt

Відповіді:


240

auto- це старе ключове слово C, яке означає "локальна область". auto aте саме auto int a, що і тому що локальна область є типовою для змінної, оголошеної всередині функції, вона також є такою ж, як int aу цьому прикладі.

Це ключове слово насправді є залишком від попередника B, де не було базових типів: все було int, вказівник на intмасив int. (*) Декларації були б autoабо extrn[sic]. C успадкував intправило "все є " як правило за замовчуванням, щоб ви могли оголосити цілі числа

auto a;
extern b;
static c;

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

unsigned d;  // actually unsigned int

що все ще поширене в сучасному коді.

C ++ 11 повторно використовував ключове слово, яке мало, якщо будь-який програміст C ++ використовував з оригінальним значенням для виведення його типу. Це здебільшого безпечно, оскільки intправило "все є " з C вже було скинуто в C ++ 98; єдине, що ламає, це те auto T a, що ніхто все одно не використовував. (Десь у своїх роботах про історію мови Stroustrup коментує це, але я зараз не можу знайти точну довідку.)

(*) Обробка рядків у B була цікавою: ви б використовували масиви intта запаковували кілька символів у кожен член. B насправді був BCPL з різним синтаксисом.


7
Ні, це не є законним C з 1999 року. Жоден гідний сучасний компілятор C цього не дозволяє.
Єнс Гуведт

18
@JensGustedt VS не претендує на надання сучасного компілятора C. З усіх поглядів, робота над компілятором C припинилася багато років тому; вони постачають його лише для того, щоб люди могли продовжувати складати застарілий код. (І звичайно, будь-який гідний сучасний компілятор C матиме можливість підтримувати застарілий код. У тому числі варіант для K&R C.)
James Kanze

23
@JensGustedt: ви впевнені? GCC і Clang попереджають про це в режимі C99, але вони не вважають це помилкою, окрім як -Werror.
Фред Фоо

2
@larsman, так, в 6.7.2 для цього є явне обмеження: принаймні один специфікатор типу повинен бути вказаний у специфікаторах декларації в кожній декларації ...
Jens Gustedt

40
@JensGustedt - re Ні, це не є законним C з 1999 року. Жоден гідний сучасний компілятор C не дозволяє цього. Перше твердження правильне; це незаконно з 1999 року. ІМХО, друге твердження є невірним. Будь-який гідний сучасний компілятор C повинен це дозволити. Подивіться на всі застарілі коди, які повинні були бути переписані, якби вони цього не дозволяли. Я написав відповідь, яка розширює цей коментар.
Девід Хаммен

35

Це і відповідь, і розширений коментар до Ні, це не є законним C з 1999 року. Жоден гідний сучасний компілятор C не дозволяє цього.

Так, auto a=1;це незаконно в С1999 (а також C2011). Тільки тому, що це зараз незаконно, не означає, що сучасний компілятор C повинен відхиляти код, який містить такі конструкції. Я б заперечив протилежне, що гідний сучасний компілятор C повинен все-таки це дозволити.

І clang, і gcc роблять саме це під час компіляції зразкового коду у питанні проти версій стандарту 1999 або 2011 років. Обидва укладачі видають діагностику, а потім продовжують, як ніби було заперечне твердження auto int a=1;.

На мою думку, саме це повинен зробити гідний компілятор. Випускаючи діагностику, clang та gcc повністю відповідають стандарту. Стандарт не говорить про те, що компілятор повинен відхиляти незаконні коди. Стандарт просто говорить, що відповідна реалізація повинна виробляти принаймні одне діагностичне повідомлення, якщо блок перекладу містить порушення будь-якого синтаксичного правила або обмеження (5.1.1.3).

Враховуючи код, який містить незаконні конструкції, будь-який гідний компілятор намагатиметься осмислити незаконність коду, щоб компілятор міг знайти наступну помилку в коді. Компілятор, який зупиняється на першій помилці, не дуже хороший компілятор. Існує спосіб зрозуміти сенс auto a=1, який полягає у застосуванні правила "неявна int". Це правило змушує компілятора інтерпретувати auto a=1так, ніби це було, auto int a=1коли компілятор використовується в режимі C90 або K&R.

Більшість компіляторів зазвичай роблять код відхилення (reject: відмовляються генерувати об’єктний файл або виконуваний файл), що містить незаконні синтаксиси. Це випадок, коли автори-компілятори вирішили, що відмова від компіляції - не найкращий варіант. Найкраще це зробити діагностику, виправити код і продовжувати. Занадто багато застарілого коду, наповненого такими конструкціями, як register a=1;. Компілятор повинен мати можливість скласти цей код у режимі C99 або C11 (звичайно, з діагностикою).


1
@larsmans - я бачу, звідки ти родом. Ви хочете -ffs-please-stop-allowing-constructs-from-some-previous-millenniumваріант компілятора, або, більш коротко, -fstrict-complianceваріант. Нарікаючи на компілятор: "Коли я використовував -std = c11, я не сподівався, що давній круфт K&R складе. Насправді я хотів, щоб він не компілювався!"
Девід Хаммен

1
На насправді немає , немає, я хочу, щоб повернути на прапор , щоб отримати найгірший мотлох для компіляції. Але -std=c99бути більш суворим було б кроком у правильному напрямку :)
Фред Фоо

1
Якщо ви використовуєте gcc -g -O3 -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror(що я звичайно використовую, навіть за кодом із запитань про SO), то ви отримуєте досить близьке до того, що хочете. Я хотів би, щоб GCC за замовчуванням принаймні -std=c99і бажано -std=c11(або, -std=gnu11вони, швидше за все, зробили це), але до цього часу ... Ви можете налаштувати ці варіанти; -pedantic, -Wshadow, -Wold-style-declarationІ деякі інші можуть бути корисні, але це хороший стартовий набір опцій.
Джонатан Леффлер

3
@DavidHammen: Ні цикломатична складність, ні керівники проектів, ні політика компанії не є елементами мови.
Джеррі Б

3
Прапор, щоб отримати поведінку, яку ви хочете в GCC,-pedantic-errors
τεκ

29

autoмає значення як у Стандарті 2011 року, так Cі C++раніше. Це означає, що змінна має автоматичний термін служби, тобто термін експлуатації, що визначається областю . Цьому протистоїть, наприклад, staticчас життя, коли змінна триває "назавжди", незалежно від сфери застосування. auto- це термін служби за замовчуванням, і майже ніколи не чітко прописано. Ось чому було безпечно змінити значення в C++.

Тепер C, перед стандартом 99, якщо ви не вказали тип змінної, вона за замовчуванням int.

Тож із auto a = 1;вами ви декларуєте (і визначаєте) intзмінну, час життя визначається сферою.

("Термін служби" правильніше називати "тривалістю зберігання", але я вважаю, що це, мабуть, менш зрозуміло).


Гаразд, тому фактично auto a = 1 дозволено в C і означає змінну int з автоматичною тривалістю зберігання.
lee77

1
Власне, "тривалість зберігання" приймає одне зі списку значень, "автоматичне", "статичне", "динамічне", "потокове". «Термін експлуатації» - це фактичний час життя об’єкта. Таким чином, змінна має тривалість зберігання "автоматична" і термін служби "тривалість сфери mainфункції".
Стів Джессоп

@Так, так, я не мав на увазі цього autoі staticє єдиними двома можливостями. Я намагався написати свою відповідь способом, орієнтованим на запитувача, який, здається, є доволі новим для C++C), тому я трохи оглянув деталі. Можливо, це була погана ідея; їх потрібно рано чи пізно прикрити.
BoBTFish

1
@BoBTFish: о, я не скаржився на це. Я просто мав на увазі розширити смислову різницю між "тривалістю життя", яка є тривалістю, та "тривалістю зберігання", яка може бути більш точно названа "категорією тривалості зберігання".
Стів Джессоп

Цей неявний intматеріал видалено з «С» з 1999 року.
Єнс Гуведт

8

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

Історично C дозволяло оголошення змінних без специфікатора типу; тип за замовчуванням до int. Тож ця декларація рівнозначна

int a=1;

Я думаю, що це є застарілим (і, можливо, забороненим) у сучасному С; але деякі популярні компілятори за замовчуванням C90 (що, я думаю, це дозволяє), і, що дратує, включають попередження лише тоді, коли ви спеціально їх запитаєте. Компіляція з GCC та вказівка ​​C99 з -std=c99, або ввімкнення попередження з -Wallабо -Wimplicit-int, дає попередження:

warning: type defaults to int in declaration of a

4
Це дійсно заборонено в С з 1999 року.
Єнс Гуведт

5

У C autoозначає, що те ж саме registerробить у C ++ 11: це означає, що змінна має автоматичну тривалість зберігання.

І в C до початку C99 (а компілятор Microsoft не підтримує ані C99, ані C11, хоча він може підтримувати його частини) тип може бути пропущено у багатьох випадках, коли це буде за замовчуванням int.

Він взагалі не приймає тип від ініціалізатора. Ви щойно вибрали сумісний ініціалізатор.


1
Чи не застаріле ключове слово реєстру в C ++ 11?
похмурий

@sordid Так, так. До C ++ 11, autoі registerбув точно такий же сенс (я раніше зауважив , що там були обмеження на прийняття registerадреси -qualified змінної, але це невірно для C ++). register, поки застаріла, поки що зберігає своє старе значення.

5
@JensGustedt: У відповіді не сказано, що вони є. Це говорить про те, що autoв C означає те саме, що і registerв C ++, що це робиться (і середнє значення тривалості автоматичного зберігання, і більше нічого).
Майк Сеймур

3

Тип компіляції візуальної студії доступний за адресою right click on file -> Properties -> C/C++ -> Advanced -> Compile As. Щоб переконатися, що він скомпільований як /TCваріант сили C. Тоді в цьому випадку це те, про що говорили larsmans (старе autoключове слово C ). Він може бути складений як C ++ без того, щоб ви знали.


3

Клас зберігання визначає сферу (видимість) та час життя змінних та / або функцій в межах програми C.

Існують такі класи зберігання, які можна використовувати в програмі С

auto
register
static
extern

auto - клас зберігання за замовчуванням для всіх локальних змінних.

{
        int Count;
        auto int Month;
}

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

intтиповим типом є autoкод нижче:

auto Month;
/* Equals to */
int Month;

Нижче код також є законним:

/* Default-int */
main()
{
    reurn 0;
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.