Почему auto a=1; компилировать на С?

Код:

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

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

Означает ли это, что мой компилятор не придерживается C, или код на самом деле правильный на языке C?


person lee77    schedule 01.05.2014    source источник
comment
Либо вы компилируете в режиме C++ (возможно), либо MS все еще застряла в прошлом тысячелетии. Неявный int был удален из стандарта C в 1999 году.   -  person Jens Gustedt    schedule 01.05.2014
comment
The code gets compiled without errors by the MS Visual Studio 2012 compiler - что происходит, когда вы включаете предупреждения?   -  person Brandin    schedule 01.05.2014
comment
@JensGustedt MSVC++ поддерживает только C89 (и некоторые функции из C99). Это скорее компилятор C++.   -  person ntoskrnl    schedule 01.05.2014
comment
@Brandin: с параметром /Wall выдается предупреждение C4431, в котором говорится, что спецификатор типа отсутствует и что int по умолчанию больше не поддерживается в C (см. комментарий Дженса). Это немного противоречие, поскольку очевидно, что этот компилятор поддерживает его...   -  person lee77    schedule 01.05.2014
comment
@JensGustedt По этим меркам GCC 4.7, выпущенный в 2012 году (и более поздние версии, я подозреваю, у меня их нет под рукой) также застрял в прошлом тысячелетии. Он компилирует код OP даже без уведомления, если ему не заданы какие-либо флаги.   -  person    schedule 01.05.2014
comment
@delnan, я как минимум предполагал, что ОП включил уровни предупреждений. Я, очевидно, был неправ. И в некотором смысле это правда, gcc также все еще застрял там, поскольку у них все еще нет C99 (или его варианта) по умолчанию. clang предупреждает о конструкции даже без флагов.   -  person Jens Gustedt    schedule 01.05.2014
comment
MSFT публично заявили, что обновление компилятора C, поставляемого с Visual Studio, даже не входит в их планы. Вот почему несколько проектов с открытым исходным кодом, которые должны компилироваться как на *n?x, так и на Windows, привязаны к C89.   -  person kahen    schedule 04.05.2014
comment
Это было задано в Reddit reddit.com/r/programming/comments/24mvym/ , #простоговорю.   -  person motiur    schedule 05.05.2014
comment
К счастью, MS совсем недавно передумала и заявила, что будет поддерживать C99. Хотя тянули их достаточно долго...   -  person Craig Ringer    schedule 05.05.2014
comment
@JensGustedt Это правда, что через 15 лет можно было бы ожидать C99 по умолчанию. С другой стороны, это может быть просто признанием реальности: многие люди, использующие C, застряли в прошлом. В отличие от сообщества C++ (которое запрыгивает на подножку C++11 еще до того, как большинство компиляторов успеют его реализовать), большая часть сообщества C, кажется, вполне довольна C90 и не слишком заинтересована в дополнениях C99.   -  person James Kanze    schedule 06.05.2014


Ответы (7)


auto — это старое ключевое слово C, означающее «локальная область». auto a совпадает с auto int a, а поскольку локальная область действия является значением по умолчанию для переменной, объявленной внутри функции, она также совпадает с int a в этом примере.

Это ключевое слово на самом деле осталось от предшественника C B, где не было базовых типов: все было int, указатель на int, массив int.(*) Объявления были либо auto, либо extrn [так в оригинале]. 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, которым все равно никто не пользовался. (Где-то в своих статьях по истории языка Страуструп комментирует это, но сейчас я не могу найти точную ссылку .)

(*) Обработка строк в B была интересной: вы использовали массивы int и упаковывали несколько символов в каждый элемент. На самом деле B был BCPL с другим синтаксисом.

person Community    schedule 01.05.2014
comment
Нет, это недопустимо для C с 1999 года. Ни один приличный современный компилятор C не допускает этого. - person Jens Gustedt; 01.05.2014
comment
@JensGustedt VS не претендует на предоставление современного компилятора C. Судя по всему, работа над компилятором Си прекратилась много лет назад; они предоставляют его только для того, чтобы люди могли продолжать компилировать устаревший код. (И, конечно же, любой достойный современный компилятор C будет иметь опции для поддержки устаревшего кода. В том числе опцию для K&R C.) - person James Kanze; 01.05.2014
comment
И, конечно же, B работал не только на PDP-11, поскольку он был разработан до появления PDP-11. - person James Kanze; 01.05.2014
comment
@JamesKanze, в этом ответе просто утверждается, что нетипизированные объявления все еще возможны в C, что бы читатель ни понимал под этим термином. Это требует корректировки. - person Jens Gustedt; 01.05.2014
comment
@JensGustedt: ты уверен? GCC и Clang предупреждают об этом в режиме C99, но они не считают это ошибкой, за исключением -Werror. - person Fred Foo; 01.05.2014
comment
@JamesKanze: я исправляюсь насчет платформ, поддерживаемых B. - person Fred Foo; 01.05.2014
comment
Я думаю, что новый gcc4.9 имеет ключевое слово auto, идентичное C++. - person this; 01.05.2014
comment
@self В журнале изменений указано, что он называется __auto_type. - person Fred Foo; 01.05.2014
comment
Это то, что я имел в виду. - person this; 01.05.2014
comment
Если память не изменяет, то, что вы больше не можете делать в C99, это a; с никакими спецификаторами или квалификаторами типа. auto a; по-прежнему действует и эквивалентно int a; - person zwol; 01.05.2014
comment
@Zack a; никогда не был декларацией, а заявлением. - person Fred Foo; 01.05.2014
comment
@larsmans В оригинальном K&R C a; было объявлением, по крайней мере, в области файла. - person James Kanze; 01.05.2014
comment
@Zack auto a недействителен ни в C99, ни в C11. - person Jens Gustedt; 01.05.2014
comment
@larsman, да, в 6.7.2 для этого есть явное ограничение: По крайней мере, один спецификатор типа должен быть указан в спецификаторах объявлений в каждом объявлении ... - person Jens Gustedt; 01.05.2014
comment
@JensGustedt: изменил ответ. - person Fred Foo; 01.05.2014
comment
@JensGustedt MSVC поддерживает только C89. - person Archie; 01.05.2014
comment
@JensGustedt - re Нет, это недопустимо для C с 1999 года. Ни один приличный современный компилятор C не допускает этого. Первое утверждение верно; он незаконен с 1999 года. ИМХО, второе утверждение неверно. Любой приличный современный компилятор C должен допускать это. Посмотрите на весь унаследованный код, который пришлось бы переписать, если бы они этого не позволяли. Я написал ответ, который расширяет этот комментарий. - person David Hammen; 01.05.2014
comment
@Jens Компилятор может принять неправильную программу. В этом случае поведение определяется реализацией. - person fuz; 04.05.2014
comment
@JamesKanze VS не претендует на предоставление современного компилятора C Я думаю, ни современный компилятор C++... - person Manu343726; 04.05.2014
comment
@ Manu343726 Manu343726 VS — относительно современный компилятор C++. Возможно, не лучший, но в целом неплохой. Компилятор C в VS, с другой стороны, предназначен только для компиляции устаревшего кода и на самом деле не пытается поддерживать что-либо более новое, чем C90. - person James Kanze; 05.05.2014
comment
@JamesKanze Не совсем так, Microsoft фактически добавила свои собственные функции безопасной обработки строк, отличные от функций в POSIX, и приняла их в C11 в качестве дополнительной библиотеки. Таким образом, они реализуют часть C11, в силу того, что их библиотека включена в стандарт. - person Fred Foo; 05.05.2014
comment
@larsmans Безопасные строковые функции - это другая проблема, поскольку <cstring> также является частью C ++. И, по крайней мере, формально, безопасные строковые функции решают другую проблему: предотвращение переполнения буфера, а не повторный вход и безопасность потоков. Откуда суффикс _s, а не _r. (Но существует достаточно совпадений, и хотелось бы, чтобы к ним обращались вместе с общим именем.) - person James Kanze; 06.05.2014
comment
@JamesKanze Я оставлю свое мнение о дизайне функций _s при себе, но функции POSIX, о которых я говорил, на самом деле strdup, snprintf (также C99) и getline. Они образуют адекватную защиту от многих переполнений буфера, и они должны были быть в C99, но MS решила заново изобрести велосипед. Я действительно не вижу ссылки на C++, потому что в настоящее время он соответствует C99, а функции _s есть только в C11 (который MS даже не реализует). - person Fred Foo; 06.05.2014
comment
@FredOverflow: на самом деле это было написано extrn в B. Например, creat, /usr и другие униксизмы. - person Fred Foo; 06.05.2014
comment
@FredFoo, MS VC 2015 на самом деле теперь имеет snprintf (предположительно, совместимый с ISO 99) - person Sebastian; 15.04.2016

Это и ответ, и расширенный комментарий к Нет, это недопустимо для C с 1999 года. Ни один приличный современный компилятор C не допускает этого.

Да, auto a=1; является незаконным в C1999 (а также 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.

Большинство компиляторов обычно отклоняют код (отклонение: отказ в создании объектного файла или исполняемого файла), который содержит недопустимый синтаксис. Это тот случай, когда авторы компилятора решили, что неудачная компиляция — не лучший вариант. Лучше всего сделать диагностику, исправить код и продолжить. Слишком много устаревшего кода, приправленного такими конструкциями, как register a=1;. Компилятор должен уметь компилировать этот код в режиме C99 или C11 (конечно, с диагностикой).

person David Hammen    schedule 01.05.2014
comment
Я не уверен в этом. auto a=1 кажется безобидным, но чем больше ворса приобретает язык, тем сложнее ему становится понимать код, и я был бы счастлив, если бы GCC/CLang выбрал разумное подмножество C11 для компиляции без -fallow-old-cruft (без триграфов, автоматических int или int f() не эквивалентно int f(void)). - person Fred Foo; 02.05.2014
comment
@larsmans - Концептуально, в чем разница между auto a; и register a? Вы, вероятно, не увидите много объявлений формы auto a в устаревшем коде, но вы наверняка увидите много объявлений формы register a в устаревшем коде. Я видел volatile register foo; в устаревшем коде C. Подскажите как это понять! - person David Hammen; 02.05.2014
comment
Разница в частоте, я думаю, хотя я тоже не вижу такой большой register a. Я все еще вижу объявления K&R с неявными аргументами int, и я бы хотел, чтобы компилятор просто отказался от этого хлама. - person Fred Foo; 02.05.2014
comment
@larsmans - я понимаю, откуда вы. Вам нужна опция компилятора -ffs-please-stop-allowing-constructs-from-some-previous-millennium или, короче, опция -fstrict-compliance. Ворчание на компилятор: Когда я использовал -std=c11, я не ожидал, что этот древний K&R kruft скомпилируется. На самом деле я хотел, чтобы он не компилировался! - person David Hammen; 02.05.2014
comment
На самом деле нет, я хочу включить вкл флаг, чтобы компилировать наихудший хлам. Но -std=c99 быть более строгим было бы шагом в правильном направлении :) - person Fred Foo; 02.05.2014
comment
Если вы используете 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 и некоторые другие могут быть полезны, но это хороший начальный набор параметров. - person Jonathan Leffler; 02.05.2014
comment
Мне нравятся строгие флаги компиляции, но я не фанат -Werror. Вместо этого мне нравится правило, в котором говорится, что компилируется по крайней мере с этим набором флагов: ‹пропущено›. Любые предупреждения, сгенерированные компилятором, должны быть явно одобрены в письменной форме руководителем проекта и записаны в журнал отказов. Кстати, проще получить вейвер на функцию с цикломатической сложностью 600, чем на предупреждение компилятора. - person David Hammen; 02.05.2014
comment
@DavidHammen: Ни цикломатическая сложность, ни менеджеры проектов, ни политика компании не являются элементами языка. - person Jerry B; 04.05.2014
comment
Флаг для получения желаемого поведения в GCC: -pedantic-errors - person τεκ; 04.05.2014
comment
На мой взгляд, это то, что должен делать приличный компилятор. Неявный int был удален из языка по какой-то причине. Такой код был плохим задолго до C99. Хороший компилятор не позволяет компилировать плохой код. В остальном этот ответ хорош, если бы не эти мнения, он бы проголосовал за него. - person Lundin; 20.08.2018

auto имел значение в C и C++ до Стандарта 2011 года. Это означает, что переменная имеет автоматическое время жизни, то есть время жизни, определяемое областью действия. Это противоположно, например, static времени жизни, когда переменная существует «вечно», независимо от области действия. auto — это время жизни по умолчанию, и оно почти никогда не указывается явно. Вот почему было безопасно изменить значение C++.

Теперь в C, до стандарта 99, если вы не укажете тип переменной, по умолчанию используется int.

Таким образом, с помощью auto a = 1; вы объявляете (и определяете) переменную int, время жизни которой определяется областью действия.

(«время жизни» правильнее называть «длительностью хранения», но я думаю, что это, возможно, менее ясно).

person BoBTFish    schedule 01.05.2014
comment
Итак, на самом деле auto a=1 разрешено в C и означает переменную типа int с автоматическим временем хранения. - person lee77; 01.05.2014
comment
Правильно, продолжительность хранения принимает одно из списка значений: автоматический, статический, динамический, поток. Время жизни – это фактическое время жизни объекта. Таким образом, переменная имеет автоматическую продолжительность хранения, а время жизни - продолжительность области действия функции main. - person Steve Jessop; 01.05.2014
comment
@ Стив, да, я не имел в виду, что auto и static - единственные две возможности. Я пытался написать свой ответ таким образом, чтобы он был нацелен на спрашивающего, который, кажется, довольно плохо знаком с C++C), поэтому я немного упустил детали. Может быть, это была плохая идея; их нужно рано или поздно закрывать. - person BoBTFish; 01.05.2014
comment
@BoBTFish: о, я не жаловался на это. Я просто хотел уточнить семантическое различие между временем жизни, которое представляет собой продолжительность, и продолжительностью хранения, которую более точно можно было бы назвать категорией продолжительности хранения. - person Steve Jessop; 01.05.2014
comment
Этот неявный материал int удален из C с 1999 года. - person Jens Gustedt; 01.05.2014

В C и исторических диалектах C++ auto — это ключевое слово, означающее, что a имеет автоматическое хранение. Поскольку его можно применять только к локальным переменным, которые по умолчанию являются автоматическими, его никто не использует; Вот почему C++ изменил назначение этого ключевого слова.

Исторически C допускал объявления переменных без спецификатора типа; тип по умолчанию int. Таким образом, это объявление эквивалентно

int a=1;

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

warning: type defaults to ‘int’ in declaration of ‘a’
person Mike Seymour    schedule 01.05.2014
comment
Это действительно запрещено в C с 1999 года. - person Jens Gustedt; 01.05.2014

В C auto означает то же самое, что register в C++11: это означает, что переменная имеет автоматический срок хранения.

А в C до C99 (а компилятор Microsoft не поддерживает ни C99, ни C11, хотя может поддерживать их части) во многих случаях этот тип можно опустить, где по умолчанию он будет равен int.

Он вообще не берет тип от инициализатора. Вы случайно выбрали совместимый инициализатор.

person Community    schedule 01.05.2014
comment
Разве ключевое слово register не устарело в С++ 11? - person sordid; 01.05.2014
comment
@sordid Да, это так. До C++11 auto и register имели точно такое же значение (ранее я отмечал, что существуют ограничения на получение адреса переменной с указанием register, но это неверно для C++). register, хотя и устарел, пока сохраняет свое старое значение. - person ; 01.05.2014
comment
@JensGustedt: ответ не говорит, что они есть. В нем говорится, что auto в C означает то же самое, что и register в C++, что и происходит (оба означают продолжительность автоматического хранения и ничего больше). - person Mike Seymour; 01.05.2014

Тип компиляции Visual Studio доступен по адресу right click on file -> Properties -> C/C++ -> Advanced -> Compile As. Чтобы убедиться, что он скомпилирован как C, используйте опцию /TC. Тогда в этом случае это то, что сказал larsmans (старое ключевое слово C auto). Он может быть скомпилирован как C++ без вашего ведома.

person UmNyobe    schedule 01.05.2014

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

Существуют следующие классы хранения, которые можно использовать в программе 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;
}
person Amir Saniyan    schedule 07.05.2014