"Moderne Programmiermethoden in der Sprache C" ----Kapitel VII Grundlegende Typen

Kapitel 7 Grundtypen

7.1 Integer-Typen

Die Reihenfolge der Spezifizierer spielt keine Rolle, daher ist unsigned short int dasselbe wie short unsigned int.

Der Standard verlangt, dass der Typ int nicht kürzer als der Typ short int und der Typ long int nicht kürzer als das Segment vom Typ int sein darf. Der Wertebereich des Typs short int kann jedoch derselbe sein wie der des Typs int, und der Wertebereich des Typs int kann auch derselbe sein wie der des Typs long int.

Hinweis: Unabhängig vom Typ wird ihr Wertebereich nicht vom C-Standard vorgeschrieben und variiert von Compiler zu Compiler. Für eine bestimmte Implementierung besteht eine Möglichkeit, den Bereich der Ganzzahltypen zu bestimmen, darin, den <limits.h>-Header zu untersuchen. Dieser Header ist Teil der Standardbibliothek und definiert Makros, die die Maximal- und Minimalwerte jedes Integer-Typs darstellen.

7.1.2 Ganzzahlkonstanten

Oktalkonstanten enthalten nur Zahlen von 0 bis 7 und müssen mit 0 beginnen.

Hexadezimale Konstanten enthalten Zahlen von 0 bis 9 und Buchstaben von a bis f und beginnen immer mit 0x.

Hinweis: Buchstaben in hexadezimalen Konstanten können entweder groß oder klein geschrieben werden.

Um den Compiler zu zwingen, die Konstante als Long-Integer zu behandeln, fügen Sie einfach einen Buchstaben L (oder l) dahinter.Um anzuzeigen, dass es sich um eine vorzeichenlose Konstante handelt, können Sie die Buchstaben U (oder u), U und L hinzufügen nach der Konstante Kann in Kombination verwendet werden (Reihenfolge und Fall der Buchstaben U und L spielen keine Rolle).

7.1.4 Ganzzahlüberlauf

Das Verhalten des Programms bei Überlauf bei vorzeichenbehafteter Integer-Arithmetik ist undefiniert.

Wenn während der vorzeichenlosen Ganzzahlarithmetik ein Überlauf auftritt, ist das Ergebnis wohldefiniert: Die richtige Antwort ist Modulo 2 n , wobei n die Anzahl der Bits ist, die zum Speichern des Ergebnisses verwendet werden. Wenn Sie beispielsweise 1 zu dem vorzeichenlosen 16-Bit-Wert 65535 hinzufügen, ist das Ergebnis garantiert 0.

7.1.5 Ganzzahlen lesen/schreiben

Angenommen, es gibt ein Programm, das nicht funktioniert, weil eine der int-Variablen überläuft. Unsere erste Reaktion war, den Variablentyp von int auf long int zu ändern. Aber damit nicht genug, wir müssen auch die Auswirkungen der Datentypänderung auf andere Programmteile prüfen, insbesondere ob die Variable im Aufruf der printf-Funktion oder der scanf-Funktion verwendet wird. Falls verwendet, müssen Sie den Formatstring des Aufrufs ändern, da %d nur mit int-Typen funktioniert.

  • Verwenden Sie beim Lesen/Schreiben von Ganzzahlen ohne Vorzeichen die Buchstaben u, o oder x anstelle von d in der Konvertierungsspezifikation. Wenn der Spezifizierer u verwendet wird, wird die Zahl dezimal gelesen und geschrieben, wobei o für oktal und x für hexadezimal steht.

  • Stellen Sie beim Lesen oder Schreiben von Short Integers d, o, u oder x das Zeichen h voran.

  • Wenn Sie lange Ganzzahlen lesen oder schreiben, stellen Sie d, o, u oder x das Zeichen l voran.

  • (C99) Stellen Sie beim Lesen oder Schreiben von langen ganzen Zahlen d, o, u oder x den Buchstaben ll voran.

7.2 Fließkommatypen

long double unterstützt extrem hohe Präzisionsanforderungen und wird selten verwendet.

7.2.1 Fließkommakonstanten

Standardmäßig werden Gleitkommakonstanten mit doppelter Genauigkeit gespeichert.

Um anzuzeigen, dass nur einfache Genauigkeit erforderlich ist, kann der Buchstabe F oder f am Ende der Konstante hinzugefügt werden; um anzuzeigen, dass die Konstante im langen Doppelformat gespeichert werden muss, kann der Buchstabe L oder l am Ende der hinzugefügt werden Konstante.

7.2.2 Fließkommazahlen lesen/schreiben

Die Konvertierungsbezeichner %e, %f und %g werden zum Lesen und Schreiben von Gleitkommazahlen mit einfacher Genauigkeit verwendet.

C99 erlaubt %le, %lf und %lg in printf-Funktionsaufrufen, aber der Buchstabe l hat keine Auswirkung.

7.3 Zeichentypen

Zeichenkonstanten müssen in einfache Anführungszeichen eingeschlossen werden, nicht in doppelte Anführungszeichen.

7.3.2 Zeichen mit und ohne Vorzeichen

Standard C erlaubt die Verwendung der Wörter signed und unsigned, um den Zeichentyp zu ändern:

unsigned char x;
signed char x;

Portabilitätstricks Gehen Sie nicht davon aus, dass der Zeichentyp standardmäßig signiert oder unsigniert ist. Wenn es einen Unterschied macht, ersetzen Sie char durch signed char oder unsigned char.

7.3.4 Übertragungsreihenfolge

Name Fluchtabfolge
Alarmsymbol (Glocke). \a
Fallback-Charakter \b
Formular-Feed \f
Neue Zeile \n
Wagenrücklauf \r
horizontaler Reiter \t
vertikale Registerkarte \v
Backslash \\
Fragezeichen ?
Apostroph \'
Anführungszeichen \"
  • Eine oktale Escape-Sequenz besteht aus dem Zeichen \ gefolgt von einer oktalen Zahl mit bis zu drei Ziffern. (Die Zahl muss als vorzeichenloses Zeichen dargestellt werden, daher beträgt der Höchstwert normalerweise 377 in Oktalform.) Das Escape-Zeichen kann beispielsweise als \33 oder \033 geschrieben werden. Im Gegensatz zu Oktalkonstanten müssen Oktalzahlen in Escape-Sequenzen nicht mit 0 beginnen.
  • Eine hexadezimale Escape-Sequenz besteht aus \x gefolgt von einer hexadezimalen Ziffer. Obwohl Standard-C keine Begrenzung für die Anzahl der Stellen in einer Hexadezimalzahl hat, muss sie als vorzeichenloses Zeichen dargestellt werden (wenn die Zeichenlänge also 8 Bit beträgt, darf der Wert der Hexadezimalzahl FF nicht überschreiten). Mit dieser Notation können Fluchtzeichen als \x1b oder \x1B geschrieben werden. Das Zeichen x muss in Kleinbuchstaben geschrieben werden, aber bei Hexadezimalzahlen (z. B. b) wird die Groß-/Kleinschreibung nicht beachtet. x kann nicht weggelassen werden.

7.3.5 Zeichenbehandlungsfunktionen

Die Funktion toupper() prüft beim Aufruf, ob der Parameter ein Kleinbuchstabe ist und wandelt den Parameter gegebenenfalls in den entsprechenden Großbuchstaben um, ansonsten gibt die Funktion den Wert des Parameters zurück.

Das Programm, das die toupper-Funktion aufruft, sollte Vorverarbeitungsanweisungen hinzufügen und die entsprechende Header-Datei <ctype.h> enthalten.

7.3.6 Lesen/Schreiben von Zeichen mit scanf und printf

Die scanf-Funktion überspringt keine Leerzeichen. Um die scanf-Funktion zu zwingen, Leerzeichen vor dem Lesen von Zeichen zu überspringen, muss vor der Konvertierungsangabe %c in der Formatzeichenfolge ein Leerzeichen stehen.

Hinweis: Leerzeichen im Scanf-Format-String bedeuten „null oder mehr Leerzeichen überspringen“.

7.3.7 Lesen/Schreiben von Zeichen mit getchar und putchar

Hinweis: getchar gibt eher einen Wert vom Typ int als einen Wert vom Typ char zurück. Wie die Funktion scanf überspringt die Funktion getchar beim Lesen keine Leerzeichen.

Beim Ausführen eines Programms kann die Verwendung der Funktionen getchar und putchar viel Zeit sparen (als scanf und printf). Es gibt zwei Gründe:

  1. Diese beiden Funktionen sind viel einfacher als die scanf-Funktion und die printf-Funktion, da die scanf-Funktion und die printf-Funktion darauf ausgelegt sind, viele verschiedene Datentypen in unterschiedlichen Formaten zu lesen/schreiben.
  2. Für einen zusätzlichen Geschwindigkeitsschub werden normalerweise getchar- und putchar-Funktionen als Makros implementiert.

Redewendung:

while(getchar()!='\n')
···
while((ch = getchar())==' ')
···

7.4 Typumwandlung

Implizite Konvertierung:

  • Wenn die Operandentypen in arithmetischen Ausdrücken oder logischen Ausdrücken nicht identisch sind. (C-Sprache führt sogenannte allgemeine arithmetische Konvertierungen durch )
  • Wenn der Typ des Ausdrucks auf der rechten Seite des Zuweisungsoperators nicht mit dem Typ der Variablen auf der linken Seite übereinstimmt.
  • Wenn die tatsächlichen Parametertypen in einem Funktionsaufruf nicht mit ihren entsprechenden formalen Parametertypen übereinstimmen.
  • Wenn der Typ des Ausdrucks in der return-Anweisung nicht mit dem Typ des Rückgabewerts der Funktion übereinstimmt.

7.4.1 Übliche arithmetische Umrechnungen

Integer-Promotion: Konvertiert ein Zeichen oder eine kurze Ganzzahl in den Typ int (oder in einigen Fällen unsigned int).

Es gibt zwei Fälle von Integer-Promotion:

  • Der Fall, in dem der Typ eines Operanden ein Fließkommatyp ist . Operanden mit schmaleren Typen werden wie folgt heraufgestuft:

    Bild-20220303161659570

Hinweis: Solange eines der Daten links und rechts vom binären Operator von einem bestimmten Typ ist, wird der andere Typ mit einer niedrigeren Ebene hochkonvertiert. Das heißt, wenn ein Operand vom Typ Long Double ist, dann ist der andere Operand vom Typ Long Double.

  • Der Fall, in dem der Typ beider Operanden kein Fließkommatyp ist. Führen Sie zuerst eine Integer-Promotion für seine beiden Operanden durch (stellen Sie sicher, dass keiner der Operanden vom Typ char oder short ist). Dann werden die Operanden mit schmaleren Typen gemäß der folgenden Abbildung hochgestuft:

    Bild-20220303162706100

    Es gibt einen Sonderfall, der nur auftritt, wenn long int und unsigned int dieselbe Länge haben (z. B. 36 Bit). Wenn in diesem Fall ein Operand vom Typ long int und der andere vom Typ unsigned int ist, werden beide Operanden in den Typ unsigned long int umgewandelt.

    Hinweis: Die Operanden der Funktionen strlen() und sizeof() sind vom Typ unsigned int.

7.4.2 Konvertierung während der Zuordnung

Übliche arithmetische Konvertierungen gelten nicht für Zuweisungsoperationen. Die C-Sprache folgt einer weiteren einfachen Konvertierungsregel, die darin besteht, den Ausdruck auf der rechten Seite einer Zuweisung in den Typ der Variablen auf der linken Seite umzuwandeln . Wenn der Typ der Variablen mindestens so „breit“ ist wie der Typ des Ausdrucks, dann steht dieser Konvertierung nichts im Weg. Natürlich führt die Zuweisung eines Werts eines bestimmten Typs zu einer Variablen eines engeren Typs auch zu unsinnigen Ergebnissen.

Unten ist ein Beispiel:

int a = 0;
unsigned x = 5;
int y = 5;
a = x + y;
//上面这个表达式将会发生两次类型转换,第一次,y将从有符号类型转换为有符号类型,第二次,x+y表达式的结果,将从无符号类型转换成有符号类型。

7.4.3 Implizite Konvertierungen in C99

Um Konvertierungsregeln zu definieren, erlaubt C99, dass jeder Integer-Typ eine "Integer-Konvertierungsebene" hat. Unten aufgeführt in der Reihenfolge vom höchsten zum niedrigsten.

  1. long long int, unsigned long long int
  2. long int, unsigned long int
  3. int, unsigned int
  4. short int, unsigned short int
  5. char,signed char,unsigned char
  6. _Bool

C99 ersetzt die Integer-Promotions in C89 durch Integer-Promotions, die jede Art von Rang niedriger als int und unsigned int in itn (solange alle Werte dieses Typs durch den Typ int dargestellt werden können) oder unsigned int umwandeln können.

Die Regeln für die Durchführung gängiger arithmetischer Substitutionen in C99 können in zwei Fälle unterteilt werden:

  • Der Fall, in dem der Typ eines Operanden ein Fließkommatyp ist. Solange keiner der Operanden komplex ist, gelten die gleichen Regeln wie zuvor.
  • Der Fall, in dem der Typ beider Operanden kein Fließkommatyp ist. Die Integer-Promotion wird zuerst an den beiden Zahlen durchgeführt.Wenn die beiden Operanden zu diesem Zeitpunkt vom gleichen Typ sind, endet der Prozess. Andernfalls werden die folgenden Regeln der Reihe nach ausprobiert, und es werden keine anderen Regeln berücksichtigt, sobald eine anwendbare Regel auftritt:
    • Wenn beide Operanden vorzeichenbehaftet oder beide vorzeichenlos sind, konvertieren Sie den Operanden der niedrigeren ganzzahligen Konvertierungsebene in den Typ des Operanden der höheren Ebene.
    • Wenn der Rang der vorzeichenlosen Zahl größer oder gleich dem Rang des vorzeichenbehafteten Operanden ist, konvertieren Sie den vorzeichenbehafteten Operanden in den Typ des vorzeichenlosen Operanden.
    • Konvertiert den vorzeichenlosen Operanden in den vorzeichenbehafteten Operandentyp, wenn der vorzeichenbehaftete Operandentyp alle Werte des vorzeichenlosen Operandentyps darstellen kann.
    • Konvertieren Sie andernfalls beide Operanden in den vorzeichenlosen Typ, der dem Typ des vorzeichenbehafteten Operanden entspricht.

Außerdem können == alle arithmetischen Typen in den Typ _Bool konvertiert werden. == Das Ergebnis der Konvertierung ist 0, wenn der ursprüngliche Wert 0 ist, ansonsten ist das Ergebnis 1.

7.4.4 Nötigung

  1. Die C-Sprache behandelt (Typname) als unären Operator. Unäre Operatoren haben eine höhere Priorität als binäre Operatoren. Der Compiler setzt also den Ausdruck

    (float)dividend / divisor
    

    Interpretiert als

    ((float)dividend)/divisor
    
  2. Manchmal ist es notwendig, Umwandlungen zu verwenden, um einen Überlauf zu vermeiden.

    long i;
    int j = 1000;
    i = j*j;
    

    Wenn zwei Werte vom Typ int multipliziert werden, sollte das Ergebnis ebenfalls vom Typ int sein, aber das Ergebnis von j*j ist zu groß, um als ein int-Typ auf der Maschine dargestellt zu werden, was zu einem Überlauf führt. In diesem Fall vom Typ Cast Konvertierung kann verwendet werden, um dies zu vermeiden.

    i = (long)j*j;
    

7.5 Typdefinition

Eine Typdefinition kann einen neuen Typ festlegen.

typedef int Bool;

==Hinweis: Der Name des Typs, der definiert wird, steht an letzter Stelle. (#define soll den neuen Namen (den von uns verwendeten Zeichennamen) voranstellen) == Gleichzeitig setzen wir oft den ersten Buchstaben des definierten Typnamens auf Großbuchstaben.

7.5.1 Vorteile von Typdefinitionen

  1. Typdefinitionen sind leichter zu verstehen, da wir Typnamen tatsächliche Bedeutungen zuweisen können.

  2. Typdefinitionen erleichtern Programmierern das Verständnis.

  3. Typdefinitionen erzeugen neue Datentypen, im Gegensatz zu #defines, die einfach Substitutionen sind . Nachfolgend werden Beispiele gegeben:

    #define Pint int*;
    typedef int* Ptr_int;
    Pint a,b;//被替换后是这样的 int *a,b;
    Ptr_int c,d;
    

    Hier ist a ein Zeigertyp, b ein ganzzahliger Typ und c und d sind beide ganzzahlige Zeigerdatentypen.

  4. Typedef-benannte Objekte haben die gleichen Bereichsregeln wie Variablen: Typedef-Namen, die innerhalb einer Funktion definiert sind, werden außerhalb der Funktion nicht erkannt.

7.5.2 Typdefinitionen und Portabilität

Typdefinitionen können Programme portabler machen.

In C99 verwendet der <stdint.h>-Header typedefs, um ganzzahlige Typnamen zu definieren, die eine bestimmte Anzahl von Bits belegen, z. B. ist int 32_t ein vorzeichenbehafteter Typ, der genau 32 Bits belegt. Dies ist eine effiziente Möglichkeit, Programme zu definieren und portierbarer zu machen.

7.6 Die Größe des Operators

sizeof(表达式);

Notiz:

  1. Der Wert von sizeof() ist eine Ganzzahl ohne Vorzeichen, die die Anzahl der Bytes darstellt, die erforderlich sind, um den zum Typnamen gehörenden Wert zu speichern.

  2. Beim Hinzufügen eines bestimmten Datentyps nach sizeof müssen Klammern hinzugefügt werden, aber wenn ein Variablenname hinzugefügt wird, können Klammern weggelassen werden.

  3. Der sizeof()-Operator ist eine besondere Art von Operator, da der Compiler normalerweise selbst den Wert des sizeof-Ausdrucks bestimmen kann.

  4. Die Operation allgemeiner Ausdrücke wird zur Laufzeit ausgeführt, während sizeof ein Operator ist, der in der Kompilierungsphase ausgeführt wird, und alle darin enthaltenen Operationen werden nicht ausgeführt, nur der Typ des Ausdrucksergebnisses wird spekuliert, um seine Größe zu ermitteln. **Der Ausdruck in sizeof wird also nicht wirklich ausgeführt, auch wenn der Ausdruck darin Seiteneffekte hat, hat er keine Auswirkung auf die Variable. Hier ist ein Beispiel:

    Bild-20220303191022527

    Obwohl eine ++-Operation für die Variable a in den Klammern sizeof() ausgeführt wird, bleibt a immer noch unverändert.

    Hinweis: In C89 kann der Compiler normalerweise selbst den Wert des sizeof-Ausdrucks bestimmen. Der Compiler kann jedoch die Größe eines Arrays mit variabler Länge nicht bestimmen, da die Anzahl der Elemente im Array während der Programmausführung variieren kann.

Fragen und Antworten

  1. F: %o und %x werden verwendet, um Ganzzahlen ohne Vorzeichen oktal bzw. hexadezimal zu schreiben, also wie schreibt man normale (vorzeichenbehaftete) Ganzzahlen oktal und hexadezimal?

    Antwort: Solange der Wert einer vorzeichenbehafteten Ganzzahl nicht negativ ist, kann er mit %o und %x angezeigt werden. Diese Konvertierungen bewirken, dass die print-Funktion vorzeichenbehaftete Ganzzahlen als vorzeichenlose behandelt; mit anderen Worten, die printf-Funktion geht davon aus, dass das Vorzeichenbit der Absolutwertteil der Zahl ist. Solange das Vorzeichenbit 0 ist, gibt es kein Problem.Wenn das Vorzeichenbit 1 ist, dann zeigt die Druckfunktion eine große Zahl über den Vorabruf hinaus an.

  2. F: Aber was ist, wenn die Zahl negativ ist? Wie schreibe ich es in Oktal oder Hexadezimal?

    Antwort: Wir können feststellen, ob die Zahl negativ ist, und dann selbst ein negatives Vorzeichen anzeigen:

    if(i < 0)
    	printf("-%x",-i);
    else
    	printf("%x",i);
    
  3. F: Warum sollte %lf verwendet werden, um den Wert vom Double-Typ zu lesen, aber %f verwenden, um ihn anzuzeigen?

    A: Das ist eine sehr schwer zu beantwortende Frage. Beachten Sie zunächst, dass sowohl die Funktion scanf als auch die Funktion printf ungewöhnliche Funktionen sind, da keine der beiden die Argumente der Funktion auf eine feste Zahl beschränkt. Die Funktionen scanf und prinf haben Parameterlisten variabler Länge. Beim Aufruf einer Funktion mit einer Parameterliste variabler Länge sorgt der Compiler dafür, dass der Float-Parameter automatisch in einen Double-Typ konvertiert wird, sodass die printf-Funktion nicht zwischen einem Float-Typ und einem Double-Typ-Parameter unterscheiden kann. Dies erklärt, warum %f verwendet werden kann, um sowohl einen Float- als auch einen Double-Parameter im printf-Funktionsaufruf darzustellen.

    Die Funktion scanf hingegen zeigt über einen Zeiger auf eine Variable. %f weist die Funktion scanf an, einen Wert vom Typ Float an der übergebenen Adresse zu speichern, und %lf weist die Funktion scanf an, einen Wert vom Typ Double an der Adresse zu speichern. Der Unterschied zwischen Float und Double ist hier sehr wichtig. Wenn die falsche Konvertierungsspezifikation angegeben wird, speichert die scanf-Funktion wahrscheinlich die falsche Anzahl von Bytes (nicht erwähnt, dass sich das Bitmuster vom Typ Float von dem des Typs Double unterscheiden kann).

  4. F: Was ist der Zweck der Verwendung der Escape-Sequenz ??

    Antwort: Die Escape-Sequenz ? ist verwandt mit Dreier-Zeichenfolgen, weil Dreier-Zeichenfolgen mit ?? beginnen. Wenn Sie der Zeichenfolge ein ?? hinzufügen müssen, behandelt der Compiler es wahrscheinlich als Beginn einer dreistelligen Folge. Das Ersetzen des zweiten ? durch ? löst das Problem.

  5. F: Da die getchar-Funktion schneller zu lesen ist, warum muss ich immer noch die scanf-Funktion verwenden, um ein einzelnes Zeichen zu lesen?

    Antwort: Obwohl die scanf-Funktion nicht so schnell wie getchar ist, ist sie flexibler. Wie bereits gesehen, bewirkt der Format-String „%c“, dass die scanf-Funktion das nächste Eingabezeichen liest, „%c“ liest das nächste Nicht-Leerzeichen. Außerdem ist scanf gut darin, Zeichen zu lesen, die mit anderen Datentypen gemischt sind.

  6. F: Unter welchen Umständen wandelt die Integer-Promotion ein Zeichen oder eine kurze Ganzzahl in den Typ unsigned int um?

    Antwort: Wenn die Ganzzahl vom Typ int nicht groß genug ist, um alle möglichen Werte des primitiven Typs aufzunehmen, wird die Integer-Promotion den Typ unsigned int erzeugen. Da Zeichen normalerweise 8 Bit lang sind, werden sie fast immer in int konvertiert (was garantiert mindestens 16 Bit lang ist). Signierte Shorts können immer auch in int konvertiert werden, aber unsignierte Shorts sind fragwürdig. Wenn die kurzen und regulären Ganzzahlen dieselbe Länge haben (z. B. auf 16-Bit-Computern), muss der unsigned short in unsigned int konvertiert werden, da der größte unsigned short (65535 auf 16-Bit-Computern) größer ist als der größte int Ganzzahl (32767).

  7. F: Was genau passiert, wenn Sie einer Variablen einen Wert zuweisen, der außerhalb des Wertebereichs der Variablen liegt?

    Antworten:Wenn es sich um einen ganzzahligen Typ und die Variable um einen vorzeichenlosen Typ handelt, wird die überschüssige Anzahl von Bits verworfen: Wenn die Variable ein vorzeichenbehafteter Typ ist, ist das Ergebnis implementierungsdefiniert.Das Zuweisen einer vorzeichenbehafteten Zahl zu einer Integer- oder Fließkommavariablen führt zu undefiniertem Verhalten, wenn die Variable zu klein ist, um sie zu handhaben: Alles kann passieren, einschließlich Programmabbruch.

Ich denke du magst

Origin blog.csdn.net/m0_57304511/article/details/124060741
Empfohlen
Rangfolge