Warum ist auto a = 1; in C kompilieren?


125

Der Code:

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

wird vom MS Visual Studio 2012-Compiler fehlerfrei kompiliert, wenn die Datei die Erweiterung .c hat. Ich habe immer gedacht, dass bei Verwendung der Erweiterung .c die Kompilierung nach der C-Syntax und nicht nach C ++ erfolgen sollte. Darüber hinaus ist, soweit ich weiß, Auto ohne Typ nur in C ++ seit C ++ 11 zulässig , was bedeutet, dass der Typ vom Initialisierer abgeleitet wird.

Bedeutet das, dass mein Compiler nicht an C festhält, oder ist der Code in C-Sprache tatsächlich korrekt?


8
Entweder kompilieren Sie im C ++ - Modus (möglich) oder MS steckt noch im letzten Jahrtausend fest. Implicit intwurde 1999 aus dem C-Standard entfernt.
Jens Gustedt

16
@JensGustedt MSVC ++ unterstützt nur C89 (und einige Funktionen von C99). Es ist eher ein C ++ - Compiler.
ntoskrnl

3
@Brandin: Mit der Option / Wall wird die Warnung C4431 ausgegeben, die besagt, dass ein Typbezeichner fehlt und dass das Standard-Int in C nicht mehr unterstützt wird (siehe Jens 'Kommentar). Es ist ein
kleiner

4
@JensGustedt Durch diese Maßnahme steckt GCC 4.7, veröffentlicht 2012 (und auch spätere Versionen, ich vermute - ich habe diese nicht zur Hand) auch "im letzten Jahrtausend fest". Es kompiliert den OP-Code ohne Vorankündigung, wenn keine Flags angegeben werden.

3
@delnan, ich nahm zumindest an, dass das OP die Warnstufen eingeschaltet hatte. Ich habe mich offensichtlich geirrt. Und in gewissem Sinne ist dies auch so, dass gcc immer noch dort steckt, da sie immer noch nicht C99 (oder eine Variante) als Standard haben. clang warnt vor dem Konstrukt, auch ohne Flaggen.
Jens Gustedt

Antworten:


240

autoist ein altes C-Schlüsselwort, das "lokaler Bereich" bedeutet. auto aist dasselbe wie auto int aund da der lokale Bereich der Standard für eine in einer Funktion deklarierte Variable ist, ist er auch der gleiche wie int ain diesem Beispiel.

Dieses Schlüsselwort ist eigentlich ein Überbleibsel von Cs Vorgänger B, wo es keine Basistypen gab: Alles war int, Zeiger auf int, Array von int. (*) Deklarationen wären entweder autooder extrn[sic]. C hat intstandardmäßig "alles ist " geerbt , sodass Sie Ganzzahlen mit deklarieren können

auto a;
extern b;
static c;

ISO C hat dies beseitigt, aber viele Compiler akzeptieren es aus Gründen der Abwärtskompatibilität immer noch. Wenn es Ihnen unbekannt vorkommt, sollten Sie sich darüber im Klaren sein, dass eine verwandte Regel in funktioniert

unsigned d;  // actually unsigned int

was im modernen Code immer noch üblich ist.

C ++ 11 verwendete das Schlüsselwort, das nur wenige C ++ - Programmierer mit der ursprünglichen Bedeutung verwendeten, für seine Typinferenz. Dies ist größtenteils sicher, da die intRegel "Alles ist " von C bereits in C ++ 98 gelöscht wurde. Das einzige, was kaputt geht auto T a, ist , was sowieso niemand benutzt hat. (Irgendwo in seinen Artikeln über die Geschichte der Sprache kommentiert Stroustrup dies, aber ich kann momentan keine genaue Referenz finden.)

(*) Die Behandlung von intZeichenfolgen in B war interessant: Sie würden Arrays verwenden und mehrere Zeichen in jedes Mitglied packen. B war tatsächlich BCPL mit unterschiedlicher Syntax.


7
Nein, dies ist seit 1999 kein legales C mehr. Kein anständiger moderner C-Compiler erlaubt dies.
Jens Gustedt

18
@JensGustedt VS erhebt keinen Anspruch auf Bereitstellung eines modernen C-Compilers. Die Arbeit am C-Compiler wurde offenbar vor vielen Jahren eingestellt. Sie stellen es nur zur Verfügung, damit die Benutzer weiterhin Legacy-Code kompilieren können. (Und natürlich hat jeder anständige moderne C-Compiler Optionen zur Unterstützung von Legacy-Code. Einschließlich einer Option für K & R C.)
James Kanze

23
@JensGustedt: Bist du sicher? GCC und Clang warnen beide im C99-Modus davor, aber sie betrachten es nur mit als Fehler -Werror.
Fred Foo

2
@larsman, ja, in 6.7.2 gibt es dafür eine explizite Einschränkung: In jeder Deklaration muss in jeder Deklaration mindestens ein Typspezifizierer angegeben sein ...
Jens Gustedt

40
@JensGustedt - re Nein, dies ist seit 1999 kein legales C mehr. Kein anständiger moderner C-Compiler erlaubt dies. Die erste Aussage ist richtig; es ist seit 1999 illegal. IMHO ist die zweite Aussage falsch. Jeder anständige moderne C-Compiler muss dies berücksichtigen. Schauen Sie sich den gesamten Legacy-Code an, der neu geschrieben werden müsste, wenn er dies nicht zulässt. Ich habe eine Antwort geschrieben, die diesen Kommentar erweitert.
David Hammen

35

Dies ist sowohl eine Antwort als auch ein erweiterter Kommentar zu Nein, dies ist seit 1999 kein legales C mehr. Kein anständiger moderner C-Compiler erlaubt dies.

Ja, auto a=1;ist in C1999 (und auch in C2011) illegal. Nur weil dies jetzt illegal ist, bedeutet dies nicht, dass ein moderner C-Compiler Code ablehnen sollte, der solche Konstrukte enthält. Ich würde genau das Gegenteil argumentieren, dass ein anständiger moderner C-Compiler dies noch berücksichtigen muss.

Sowohl clang als auch gcc tun genau das, wenn sie den Beispielcode in der Frage mit den Versionen des Standards von 1999 oder 2011 kompilieren. Beide Compiler geben eine Diagnose aus und fahren dann fort, als ob die anstößige Aussage gewesen wäre auto int a=1;.

Meiner Meinung nach sollte ein anständiger Compiler dies tun. Durch die Ausgabe einer Diagnose entsprechen clang und gcc vollständig dem Standard. Der Standard besagt nicht, dass ein Compiler illegalen Code ablehnen muss. Der Standard besagt lediglich, dass eine konforme Implementierung mindestens eine Diagnosemeldung erzeugen muss, wenn eine Übersetzungseinheit eine Verletzung einer Syntaxregel oder -beschränkung enthält (5.1.1.3).

Bei Code, der unzulässige Konstrukte enthält, versucht jeder anständige Compiler, den unzulässigen Code zu verstehen, damit der Compiler den nächsten Fehler im Code finden kann. Ein Compiler, der beim ersten Fehler stoppt, ist kein sehr guter Compiler. Es gibt eine Möglichkeit, einen Sinn daraus zu machen auto a=1, nämlich die "implizite int" -Regel anzuwenden. Diese Regel zwingt den Compiler, so zu interpretieren, auto a=1als ob auto int a=1der Compiler im C90- oder K & R-Modus verwendet würde.

Die meisten Compiler lehnen normalerweise Code ab (ablehnen: Verweigern der Generierung einer Objektdatei oder einer ausführbaren Datei), der eine unzulässige Syntax enthält. Dies ist ein Fall, in dem die Compilerautoren entschieden haben, dass ein fehlgeschlagenes Kompilieren nicht die beste Option ist. Am besten stellen Sie eine Diagnose, korrigieren den Code und fahren fort. Es gibt einfach zu viel Legacy-Code, der mit Konstrukten wie gespickt ist register a=1;. Der Compiler sollte in der Lage sein, diesen Code im C99- oder C11-Modus zu kompilieren (natürlich mit einer Diagnose).


1
@larsmans - Ich kann sehen, woher du kommst. Sie möchten eine -ffs-please-stop-allowing-constructs-from-some-previous-millenniumCompiler-Option oder genauer gesagt eine -fstrict-complianceOption. Murren über den Compiler: "Als ich -std = c11 verwendete, hatte ich nicht erwartet, dass dieser alte K & R-Kruft kompiliert wird. Eigentlich wollte ich, dass er nicht kompiliert wird!"
David Hammen

1
Eigentlich nicht, möchte ich haben drehen auf eine Fahne , um die schlimmsten cruft zu Kompilierung zu bekommen. Aber -std=c99strenger zu sein wäre ein Schritt in die richtige Richtung :)
Fred Foo

1
Wenn Sie verwenden gcc -g -O3 -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror(was ich routinemäßig verwende, auch bei Code aus Fragen zu SO), kommen Sie dem, was Sie wollen, ziemlich nahe. Ich möchte, dass GCC mindestens -std=c99und vorzugsweise standardmäßig verwendet wird -std=c11(oder, das -std=gnu11würden sie eher tun), aber bis dahin… können Sie diese Optionen optimieren. -pedantic, -Wshadow, -Wold-style-declarationUnd einige andere können nützlich sein, aber das ist eine gute Optionen zu starten.
Jonathan Leffler

3
@DavidHammen: Weder zyklomatische Komplexität, Projektmanager noch Unternehmensrichtlinien sind Elemente der Sprache.
Jerry B

3
Die Flagge, um das gewünschte Verhalten in GCC zu erhalten, ist-pedantic-errors
τεκ

29

autohat eine Bedeutung in Cund C++vor dem Standard 2011. Dies bedeutet, dass eine Variable eine automatische Lebensdauer hat, dh eine Lebensdauer, die vom Bereich bestimmt wird . Dies steht beispielsweise der staticLebensdauer entgegen, bei der eine Variable unabhängig vom Umfang "für immer" gültig ist. autoist die Standardlebensdauer und wird fast nie explizit angegeben. Deshalb war es sicher, die Bedeutung in zu ändern C++.

Jetzt in Cvor dem 99 - Standard, wenn Sie nicht den Typ einer Variablen angeben, wird standardmäßig int.

Also mit auto a = 1;Ihnen (und definieren) eine deklarieren intVariable, mit Lebensdauer durch den Umfang bestimmt.

("Lebensdauer" wird besser als "Speicherdauer" bezeichnet, aber ich denke, das ist vielleicht weniger klar).


Okay, also ist tatsächlich auto a = 1 in C erlaubt und bedeutet eine int-Variable mit automatischer Speicherdauer.
Lee77

1
Richtig, "Speicherdauer" nimmt einen von einer Liste von Werten an, "automatisch", "statisch", "dynamisch", "Thread". "Lebensdauer" ist die tatsächliche Lebenszeit des Objekts. Die Variable hat also die Speicherdauer "automatisch" und die Lebensdauer "die Dauer des mainFunktionsumfangs".
Steve Jessop

@Steve ja, das wollte ich nicht implizieren autound staticsind die einzigen beiden Möglichkeiten. Ich habe versucht, meine Antwort so zu schreiben, dass sie sich an den Fragesteller richtet, der für C++(und C) ziemlich neu zu sein scheint , also habe ich die Details ein wenig beschönigt. Vielleicht war das eine schlechte Idee; Sie müssen früher oder später abgedeckt werden.
BoBTFish

1
@BoBTFish: Oh, darüber habe ich mich nicht beschwert. Ich wollte nur den semantischen Unterschied zwischen "Lebensdauer", die eine Dauer ist, und "Speicherdauer", die genauer als "Speicherdauer-Kategorie" bezeichnet werden könnte, erweitern.
Steve Jessop

Dieses implizite intZeug wird seit 1999 aus C entfernt.
Jens Gustedt

8

In C und in historischen Dialekten von C ++ autoist dies ein Schlüsselwort, adas automatisch gespeichert wird. Da es nur auf lokale Variablen angewendet werden kann, die standardmäßig automatisch sind, wird es von niemandem verwendet. Aus diesem Grund hat C ++ das Schlüsselwort jetzt neu verwendet.

In der Vergangenheit hat C Variablendeklarationen ohne Typspezifizierer zugelassen. Der Typ ist standardmäßig int. Diese Erklärung entspricht also

int a=1;

Ich denke, dass dies im modernen C veraltet (und möglicherweise verboten) ist; Einige beliebte Compiler verwenden jedoch standardmäßig C90 (was meiner Meinung nach dies zulässt) und aktivieren Warnungen ärgerlicherweise nur, wenn Sie ausdrücklich danach fragen. Das Kompilieren mit GCC und das Angeben von C99 mit -std=c99oder das Aktivieren der Warnung mit -Walloder -Wimplicit-intgibt eine Warnung aus:

warning: type defaults to int in declaration of a

4
Es ist in der Tat in C seit 1999 verboten.
Jens Gustedt

5

In C autobedeutet dies dasselbe registerwie in C ++ 11: Es bedeutet, dass eine Variable eine automatische Speicherdauer hat.

Und in C vor C99 (und der Compiler von Microsoft unterstützt weder C99 noch C11, obwohl er möglicherweise Teile davon unterstützt) kann der Typ in vielen Fällen weggelassen werden, wo er standardmäßig verwendet wird int.

Der Typ wird vom Initialisierer überhaupt nicht übernommen. Sie haben gerade einen kompatiblen Initialisierer ausgewählt.


1
Ist das Schlüsselwort register in C ++ 11 nicht veraltet?
schmutzig

@sordid Ja, das ist es. Vor C ++ 11 autound registerhatte genau die gleiche Bedeutung (ich habe zuvor kommentiert, dass es Einschränkungen registergab, die Adresse einer qualifizierten Variablen zu verwenden, aber das war für C ++ falsch). register, obwohl veraltet, behält seine alte Bedeutung für jetzt.

5
@JensGustedt: Die Antwort sagt nicht, dass sie es sind. Es heißt, dass autoin C dasselbe bedeutet wie registerin C ++, was es tut (beide bedeuten automatische Speicherdauer und sonst nichts).
Mike Seymour

3

Der Visual Studio-Kompilierungstyp ist unter verfügbar right click on file -> Properties -> C/C++ -> Advanced -> Compile As. Um sicherzustellen, dass es als C-Force- /TCOption kompiliert wird. In diesem Fall ist es das, was Larsmans gesagt haben (altes C- autoSchlüsselwort). Es kann ohne Ihr Wissen als C ++ kompiliert werden.


3

Eine Speicherklasse definiert den Umfang (Sichtbarkeit) und die Lebensdauer von Variablen und / oder Funktionen innerhalb eines C-Programms.

Es gibt folgende Speicherklassen, die in einem C-Programm verwendet werden können

auto
register
static
extern

auto ist die Standardspeicherklasse für alle lokalen Variablen.

{
        int Count;
        auto int Month;
}

Das obige Beispiel definiert zwei Variablen mit derselben Speicherklasse. auto kann nur innerhalb von Funktionen verwendet werden, dh innerhalb lokaler Variablen.

intist der Standardtyp für den autofolgenden Code:

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

Der folgende Code ist ebenfalls legal:

/* Default-int */
main()
{
    reurn 0;
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.