Normalerweise müssen wir in C dem Computer den Datentyp in der Variablendeklaration mitteilen. Im folgenden Programm möchte ich zB die Summe zweier Gleitkommazahlen X und Y ausgeben.
#include<stdio.h>
main()
{
float X=5.2;
float Y=5.1;
float Z;
Z=Y+X;
printf("%f",Z);
}
Ich musste dem Compiler den Typ der Variablen X mitteilen.
- Kann der Compiler den Typ nicht selbst bestimmen
X
?
Ja, das kann es, wenn ich das tue:
#define X 5.2
Ich kann jetzt mein Programm schreiben, ohne dem Compiler mitzuteilen, welche Art von X
:
#include<stdio.h>
#define X 5.2
main()
{
float Y=5.1;
float Z;
Z=Y+X;
printf("%f",Z);
}
Wir sehen also, dass die C-Sprache eine Art von Funktion hat, mit der sie den Datentyp selbst bestimmen kann. In meinem Fall wurde festgestellt, dass dies X
vom Typ float ist.
- Warum müssen wir den Datentyp angeben, wenn wir in main () etwas deklarieren? Warum kann der Compiler den Datentyp einer Variablen auf eigene in bestimmen ,
main()
wie es funktioniert in#define
.
c
variables
data-types
io
declarations
user106313
quelle
quelle
5.2
Ist adouble
, so rundet das erste Programm die doppelten Literale auffloat
Genauigkeit und fügt sie dann als Gleitkommazahlen hinzu, während das zweite Programm die doppelte Darstellung von 5.1 zurückrundetdouble
unddouble
mit derdouble
Addition zum Wert 5.2 hinzufügt und dann das Ergebnis dieser Berechnung auffloat
Genauigkeit rundet . Da die Rundung an verschiedenen Stellen auftritt, kann das Ergebnis abweichen. Dies ist nur ein Beispiel für die Arten von Variablen, die sich auf das Verhalten eines ansonsten identischen Programms auswirken.#define X 5.2
,X
handelt es sich nicht um eine Variable, sondern um eine Konstante. Sie wird also buchstäblich durch eine Präprozessor-Variable ersetzt, die Sie an einer5.2
beliebigen Stelle erwähnt habenX
. Sie können nicht neu zuweisenX
.auto
tatsächlich das, was Sie wollen). Wenn Sie jedoch glauben, dass Sie wissen, was Ihr Code tut, und tatsächlich etwas anderes eingegeben haben, wird bei einer statischen Eingabe wie dieser ein Fehler früher erkannt, bevor er zu einem großen Problem wird. Jede Sprache findet ein Gleichgewicht: statische Typisierung, Typisierungsfehler, dynamische Typisierung. Für einige Aufgaben lohnt sich die zusätzliche Eingabe. Für andere ist es eine Verschwendung.Antworten:
Sie vergleichen Variablendeklarationen mit
#define
s, was falsch ist. Mit a#define
erstellen Sie eine Zuordnung zwischen einem Bezeichner und einem Quellcode-Snippet. Der C-Präprozessor ersetzt dann alle Vorkommen dieses Bezeichners durch das bereitgestellte Snippet. SchreibenAm Ende ist es für den Compiler dasselbe wie für das Schreiben
Stellen Sie sich das als automatisiertes Kopieren und Einfügen vor.
Außerdem können normale Variablen neu zugewiesen werden, während ein mit erstelltes Makro
#define
dies nicht kann (obwohl Sie es erneut können#define
). Der AusdruckFOO = 7
wäre ein Compilerfehler, da wir keine "rvalues" zuweisen können:40 + 2 = 7
ist illegal.Warum brauchen wir überhaupt Typen? Einige Sprachen werden offenbar von Typen befreit. Dies ist besonders häufig in Skriptsprachen der Fall. Normalerweise haben sie jedoch eine so genannte dynamische Typisierung, bei der Variablen keine festen Typen haben, sondern Werte. Dies ist zwar viel flexibler, aber auch weniger performant. C mag Leistung, daher hat es ein sehr einfaches und effizientes Konzept von Variablen:
Es gibt einen Speicherbereich, der als „Stapel“ bezeichnet wird. Jede lokale Variable entspricht einem Bereich auf dem Stapel. Nun stellt sich die Frage, wie viele Bytes dieser Bereich haben muss. In C hat jeder Typ eine genau definierte Größe, über die Sie abfragen können
sizeof(type)
. Der Compiler muss den Typ jeder Variablen kennen, damit er den richtigen Speicherplatz auf dem Stapel reservieren kann.Warum brauchen Konstanten, die mit erstellt wurden,
#define
keine Typanmerkung? Sie werden nicht auf dem Stapel gespeichert.#define
Erstellt stattdessen wiederverwendbare Quellcode-Schnipsel auf eine etwas wartbarere Weise als das Kopieren und Einfügen. Literale im Quellcode wie"foo"
oder42.87
werden vom Compiler entweder inline als spezielle Anweisungen oder in einem separaten Datenabschnitt der resultierenden Binärdatei gespeichert.Literale haben jedoch Typen. Ein String-Literal ist a
char *
.42
ist einint
, kann aber auch für kürzere Typen verwendet werden (Verengungskonvertierung).42.8
wäre eindouble
. Wenn Sie ein Literal haben und möchten, dass es einen anderen Typ hat (z. B. um42.8
einfloat
oder42
ein zu machenunsigned long int
), können Sie Suffixe verwenden - einen Buchstaben nach dem Literal, der ändert, wie der Compiler dieses Literal behandelt. In unserem Fall können wir sagen ,42.8f
oder42ul
.Einige Sprachen haben eine statische Typisierung wie in C, die Typanmerkungen sind jedoch optional. Beispiele sind ML, Haskell, Scala, C #, C ++ 11 und Go. Wie funktioniert das? Zauber? Nein, dies wird als "Typinferenz" bezeichnet. In C # und Go betrachtet der Compiler die rechte Seite einer Zuweisung und leitet den Typ davon ab. Dies ist ziemlich einfach, wenn die rechte Seite ein Literal wie ist
42ul
. Dann ist es offensichtlich, welcher Typ die Variable sein soll. Andere Sprachen haben auch komplexere Algorithmen, die berücksichtigen, wie eine Variable verwendet wird. Wenn Sie dies tunx/2
,x
kann es sich nicht um eine Zeichenfolge handeln, sondern muss einen numerischen Typ haben.quelle
#define
wir eine Konstante, die direkt in Binärcode konvertiert wird - wie lang es auch sein mag - und die unverändert im Speicher abgelegt wird.#define X 5.2
?printf
undefiniertes Verhalten ausgelöst haben. Auf meinem Computer gibt dieses Snippet jedes Mal einen anderen Wert aus, auf Ideone stürzt es nach dem Drucken von Null ab.X*Y
wenn nicht gültigX
undY
sind Zeiger, aber es ist in Ordnung , wenn sie sindint
s;*X
ist nicht gültig, wennX
ist einint
, aber es ist in Ordnung, wenn es ein Zeiger ist.X im zweiten Beispiel ist niemals ein Float. Es wird als Makro bezeichnet und ersetzt den in der Quelle definierten Makrowert 'X' durch den Wert. Ein lesbarer Artikel zu #define ist hier .
Bei dem bereitgestellten Code ändert der Präprozessor den Code vor dem Kompilieren
zu
und genau das wird kompiliert.
Das bedeutet, dass Sie diese "Werte" auch durch Code wie ersetzen können
oder auch
quelle
#define FOO(...) { __VA_ARGS__ }
.Die kurze Antwort lautet: C benötigt Typen aufgrund der Historie / Darstellung der Hardware.
Geschichte: C wurde in den frühen 1970er Jahren entwickelt und ist als Programmiersprache für Systeme gedacht. Code ist idealerweise schnell und nutzt die Fähigkeiten der Hardware optimal aus.
Rückschlüsse auf Typen zur Kompilierungszeit wären möglich gewesen, die bereits langsamen Kompilierungszeiten hätten sich jedoch erhöht (siehe XKCDs "Kompilierungs" -Cartoon. Dies galt mindestens 10 Jahre nach Veröffentlichung von C für "Hallo Welt" ). Das Ableiten von Typen zur Laufzeit hätte nicht den Zielen der Systemprogrammierung entsprochen. Für die Laufzeitunterbrechung ist eine zusätzliche Laufzeitbibliothek erforderlich. C kam lange vor dem ersten PC. Welches hatte 256 RAM. Nicht Gigabyte oder Megabyte, sondern Kilobyte.
In Ihrem Beispiel, wenn Sie die Typen weglassen
Dann hätte der Compiler glücklich herausfinden können, dass X & Y Floats sind, und Z gleich gemacht. Tatsächlich würde ein moderner Compiler auch herausfinden, dass X & Y nicht benötigt werden, und einfach Z auf 10.3 setzen.
Angenommen, die Berechnung ist in eine Funktion eingebettet. Der Funktionsschreiber möchte möglicherweise sein Wissen über die Hardware oder das zu lösende Problem nutzen.
Wäre ein Double passender als ein Float? Verbraucht mehr Speicher und ist langsamer, aber die Genauigkeit des Ergebnisses wäre höher.
Möglicherweise könnte der Rückgabewert der Funktion int (oder long) sein, da die Dezimalstellen nicht wichtig waren, obwohl die Konvertierung von float nach int nicht ohne Kosten ist.
Der Rückgabewert könnte auch doppelt angegeben werden, um sicherzustellen, dass float + float nicht überläuft.
All diese Fragen scheinen für die große Mehrheit des heute geschriebenen Codes sinnlos zu sein, waren jedoch bei der Erstellung von C von entscheidender Bedeutung.
quelle
C hat keine Typinferenz (das ist es, was es heißt, wenn ein Compiler den Typ einer Variablen für Sie errät), weil es alt ist. Es wurde in den frühen 1970er Jahren entwickelt
Viele neuere Sprachen verfügen über Systeme, mit denen Sie Variablen verwenden können, ohne deren Typ anzugeben (Ruby, Javascript, Python usw.).
quelle
true
istboolean
) und keine Variablen (z. B.var x
Werte eines beliebigen Typs enthalten können). Auch die Typinferenz für solche einfachen Fälle wie die fraglichen war wahrscheinlich ein Jahrzehnt vor der Veröffentlichung von C bekannt.implicit none
in diesem Fall Sie müssen eine Art erklären.