C99 - C99

Coperta documentului de standarde C99

C99 (cunoscut anterior ca C9X ) este un nume informal pentru ISO / IEC 9899: 1999 , o versiune anterioară a standardului de limbaj de programare C. Extinde versiunea anterioară ( C90 ) cu funcții noi pentru limbă și biblioteca standard și ajută implementările să utilizeze mai bine hardware-ul computerului disponibil, cum ar fi aritmetica în virgulă mobilă IEEE 754-1985 și tehnologia compilatorului. Versiunea C11 a standardului de limbaj de programare C, publicată în 2011, înlocuiește C99.

Istorie

După ce ANSI a produs standardul oficial pentru limbajul de programare C în 1989, care a devenit un standard internațional în 1990, specificația limbajului C a rămas relativ statică de ceva timp, în timp ce C ++ a continuat să evolueze, în mare parte în timpul propriului efort de standardizare. Amendamentul normativ 1 a creat un nou standard pentru C în 1995, dar numai pentru a corecta unele detalii ale standardului din 1989 și pentru a adăuga un sprijin mai extins pentru seturile de caractere internaționale. Standardul a fost revizuit în continuare la sfârșitul anilor 1990, ducând la publicarea ISO / IEC 9899: 1999 în 1999, care a fost adoptat ca standard ANSI în mai 2000. Limbajul definit de acea versiune a standardului este denumit în mod obișnuit „ C99 ". Standardul internațional C este menținut de grupul de lucru ISO / IEC JTC1 / SC22 / WG14.

Proiecta

1999 ISO C.pdf

C99 este, în cea mai mare parte, compatibil cu C89, dar este mai strict în anumite privințe.

În special, o declarație căreia îi lipsește un specificator de tip nu mai este intimplicită. Comitetul pentru standarde C a decis că este de mai mare valoare pentru compilatori să diagnosticheze omiterea accidentală a specificatorului de tip decât să proceseze în tăcere codul vechi care se baza pe implicit int. În practică, compilatoarele sunt susceptibile să afișeze un avertisment, apoi își asumă intși continuă traducerea programului.

C99 a introdus câteva funcții noi, dintre care multe au fost deja implementate ca extensii în mai multe compilatoare:

  • funcții inline
  • declarații amestecate și cod: declarația variabilă nu mai este limitată la domeniul de aplicare al fișierului sau la începutul unei instrucțiuni compuse (bloc), facilitând formularul static unic de atribuire
  • mai multe tipuri de date noi , inclusiv long long int, tipuri întregi opționale extinse, un tip de date boolean explicit și un complextip pentru a reprezenta numere complexe
  • tablouri cu lungime variabilă (deși ulterior retrogradate în C11 la o caracteristică condițională pe care implementările nu sunt necesare pentru a le suporta)
  • membri matrice flexibile
  • suport pentru comentarii pe o linie începând cu //, ca în BCPL , C ++ și Java
  • funcții de bibliotecă noi, cum ar fi snprintf
  • noi antete , cum ar fi , , și<stdbool.h><complex.h><tgmath.h><inttypes.h>
  • matematica (macro) funcții de tip generic, în <tgmath.h>care selectați o bibliotecă de matematică funcție pe baza float, doublesau long doubleargumente, etc.
  • suport îmbunătățit pentru virgula mobilă IEEE
  • initializatori desemnate (de exemplu, inițializarea unei structuri de nume de câmpuri: struct point p = { .x = 1, .y = 2 };)
  • literals compus (de exemplu, este posibil să se structuri constructelor în funcție de apeluri: function((struct x) {1, 2}))
  • suport pentru macrocomenzi variadice (macrocomenzi cu un număr variabil de argumente)
  • restrictcalificarea permite o optimizare mai agresivă a codului , eliminând avantajele de acces la matrice în timp de compilare deținute anterior de FORTRAN față de ANSI C.
  • nume de caractere universale, care permite variabilelor utilizatorului să conțină alte caractere decât setul de caractere standard
  • cuvânt cheie staticîn indicii matricei în declarațiile parametrilor

Părți ale standardului C99 sunt incluse în versiunea curentă a standardului C ++ , inclusiv tipuri întregi, anteturi și funcții de bibliotecă. Tablourile cu lungime variabilă nu sunt printre aceste părți incluse, deoarece Biblioteca de șabloane standard C ++ include deja funcționalități similare.

Suport IEEE 754 în virgulă mobilă

O caracteristică majoră a C99 este suportul său numeric și, în special, suportul pentru accesul la caracteristicile hardware - ului IEEE 754-1985 (cunoscut și sub numele de IEC 60559) prezent în marea majoritate a procesoarelor moderne (definite în „Anexa F IEC 60559 aritmetică în virgulă mobilă "). Platformele fără hardware IEEE 754 îl pot implementa și în software.

Pe platforme cu virgulă mobilă IEEE 754:

  • floateste definit ca o singură precizie IEEE 754 , doubleeste definit ca o precizie dublă și long doubleeste definit ca o precizie extinsă IEEE 754 (de exemplu, o precizie dublă extinsă pe 80 de biți pe platformele x86 sau x86-64 ) sau o formă de precizie quad, acolo unde este disponibilă; în caz contrar, este o precizie dublă.
  • Cele patru operații aritmetice și rădăcina pătrată sunt corect rotunjite, așa cum sunt definite de IEEE 754.
    FLT_EVAL_METHOD pluti dubla lung dublu
    0 pluti dubla lung dublu
    1 dubla dubla lung dublu
    2 lung dublu lung dublu lung dublu
  • Evaluarea expresiei este definită a fi efectuată într-una din cele trei metode bine definite, indicând dacă variabilele în virgulă mobilă sunt mai întâi promovate într-un format mai precis în expresii: FLT_EVAL_METHOD == 2indică faptul că toate calculele intermediare interne sunt efectuate în mod implicit la precizie ridicată (dublu lung) acolo unde este disponibil (de ex., 80 de biți dublu extins ), FLT_EVAL_METHOD == 1efectuează toate expresiile intermediare interne cu precizie dublă (cu excepția cazului în care un operand este dublu lung), în timp ce FLT_EVAL_METHOD == 0specifică că fiecare operație este evaluată numai la precizia celui mai larg operand al fiecărui operator. Tipul de rezultat intermediar pentru operanzi cu o precizie dată este rezumat în tabelul adiacent.

FLT_EVAL_METHOD == 2tinde să limiteze riscul de rotunjire a erorilor care afectează expresiile instabile numeric (a se vedea IEEE 754 rațiunea de proiectare ) și este metoda implicită proiectată pentru hardware x87 , dar produce un comportament neintuitiv pentru utilizatorul neatent; FLT_EVAL_METHOD == 1a fost metoda implicită de evaluare utilizată inițial în K&R C , care a promovat toate flotările să se dubleze în expresii; și FLT_EVAL_METHOD == 0este, de asemenea, utilizat în mod obișnuit și specifică o „evaluare la tip” strictă a operanzilor. (Pentru gcc , FLT_EVAL_METHOD == 2este implicit pe 32 biți x86 și FLT_EVAL_METHOD == 0este implicit pe 64 biți x86-64, dar FLT_EVAL_METHOD == 2poate fi specificat pe x86-64 cu opțiunea -mfpmath = 387.) Înainte de C99, compilatoarele ar putea rotunji rezultatele intermediare inconsecvent, în special atunci când se utilizează hardware cu virgulă mobilă x87 , ducând la un comportament specific compilatorului; astfel de neconcordanțe nu sunt permise în compilatoarele conforme cu C99 (anexa F).

Exemplu

Următorul exemplu adnotat de cod C99 pentru calcularea unei funcții de fracție continuă demonstrează principalele caracteristici:

#include <stdio.h>
#include <math.h>
#include <float.h>
#include <fenv.h>
#include <tgmath.h>
#include <stdbool.h>
#include <assert.h>

double compute_fn(double z)  // [1]
{
        #pragma STDC FENV_ACCESS ON  // [2]

        assert(FLT_EVAL_METHOD == 2);  // [3]

        if (isnan(z))  // [4]
                puts("z is not a number");

        if (isinf(z))
                puts("z is infinite");

        long double r = 7.0 - 3.0/(z - 2.0 - 1.0/(z - 7.0 + 10.0/(z - 2.0 - 2.0/(z - 3.0)))); // [5, 6]

        feclearexcept(FE_DIVBYZERO);  // [7]

        bool raised = fetestexcept(FE_OVERFLOW);  // [8]

        if (raised)
                puts("Unanticipated overflow.");

        return r;
}

int main(void)
{
        #ifndef __STDC_IEC_559__
        puts("Warning: __STDC_IEC_559__ not defined. IEEE 754 floating point not fully supported."); // [9]
        #endif

        #pragma STDC FENV_ACCESS ON

        #ifdef TEST_NUMERIC_STABILITY_UP
        fesetround(FE_UPWARD);                   // [10]
        #elif TEST_NUMERIC_STABILITY_DOWN
        fesetround(FE_DOWNWARD);
        #endif

        printf("%.7g\n", compute_fn(3.0));
        printf("%.7g\n", compute_fn(NAN));

        return 0;
}

Note de subsol:

  1. Compilați cu: gcc -std=c99 -mfpmath=387 -o test_c99_fp -lm test_c99_fp.c
  2. Deoarece semnalizatoarele de stare IEEE 754 sunt manipulate în această funcție, această #pragmă este necesară pentru a evita compilatorul să rearanjeze incorect astfel de teste la optimizare. (Pragmele sunt de obicei definite de implementare, dar cele prefixate cu STDCsunt definite în standardul C.)
  3. C99 definește un număr limitat de metode de evaluare a expresiei: modul de compilare curent poate fi verificat pentru a se asigura că îndeplinește ipotezele în care a fost scris codul.
  4. Valorile speciale precum NaN și infinitul pozitiv sau negativ pot fi testate și setate.
  5. long doubleeste definit ca IEEE 754 precizie dublă extinsă sau cvadruplă, dacă este disponibilă. Folosind o precizie mai mare decât este necesar pentru calculele intermediare pot minimiza rotunjirii eroare (The typedef double_t poate fi utilizat pentru cod care este portabil sub toate FLT_EVAL_METHODs).
  6. Funcția principală care trebuie evaluată. Deși se pare că unele argumente pentru această fracție continuată, de exemplu, 3.0, ar duce la o eroare de divizare la zero, de fapt funcția este bine definită la 3.0, iar divizarea la 0 va returna pur și simplu un + infinit care va fi apoi corect duce la un rezultat finit: IEEE 754 este definit să nu prindă în mod implicit astfel de excepții și este conceput astfel încât să poată fi ignorate foarte des, ca în acest caz. (Dacă FLT_EVAL_METHODeste definit ca 2, atunci toate calculele interne, inclusiv constantele, vor fi efectuate cu o precizie dublă lungă; dacă FLT_EVAL_METHODeste definit ca 0, atunci este necesară o atenție suplimentară pentru a asigura acest lucru, incluzând eventuale exprimări suplimentare și specificarea explicită a constantelor ca dublă lungă.)
  7. Întrucât semnalizatorul divizat la zero ridicat nu este o eroare în acest caz, poate fi pur și simplu respins pentru a șterge semnalizatorul pentru a fi utilizat de codul ulterior.
  8. În unele cazuri, alte excepții pot fi considerate ca o eroare, cum ar fi depășirea (deși se poate demonstra, de fapt, că acest lucru nu poate apărea în acest caz).
  9. __STDC_IEC_559__ trebuie definit numai dacă „Anexa F IEC 60559 aritmetică în virgulă mobilă” este implementată complet de către compilator și biblioteca C (utilizatorii ar trebui să știe că această macrocomandă este uneori definită, în timp ce nu ar trebui să fie).
  10. Modul de rotunjire implicit este rotunjit la cel mai apropiat (cu regula de rotunjire uniformă în cazurile de jumătate) pentru IEEE 754, dar setarea explicită a modului de rotunjire către + și - infinit (prin definirea TEST_NUMERIC_STABILITY_UPetc. în acest exemplu, la depanare) poate fi utilizată pentru diagnosticați instabilitatea numerică. Această metodă poate fi utilizată chiar dacă compute_fn()face parte dintr-o bibliotecă binară compilată separat. Dar, în funcție de funcție, instabilitățile numerice nu pot fi întotdeauna detectate.

Detectarea versiunii

O macro standard __STDC_VERSION__este definită cu valoare 199901Lpentru a indica faptul că suportul C99 este disponibil. Ca și în cazul __STDC__macrocomenzii pentru C90, __STDC_VERSION__poate fi utilizat pentru a scrie cod care se va compila diferit pentru compilatoarele C90 și C99, ca în acest exemplu care asigură că inlineeste disponibil în ambele cazuri (prin înlocuirea acestuia cu staticîn C90 pentru a evita erorile linkerului).

#if __STDC_VERSION__ >= 199901L
  /* "inline" is a keyword */
#else
# define inline static
#endif

Implementări

Majoritatea compilatoarelor C oferă suport pentru cel puțin unele dintre caracteristicile introduse în C99.

Din punct de vedere istoric, Microsoft a întârziat să implementeze noi caracteristici C în instrumentele lor Visual C ++ , concentrându-se în principal pe sprijinirea dezvoltărilor standardelor C ++. Cu toate acestea, odată cu introducerea Visual C ++ 2013 Microsoft a implementat un subset limitat de C99, care a fost extins în Visual C ++ 2015.

Muncă viitoare

De la ratificarea standardului C din 1999, grupul de lucru pentru standarde a pregătit rapoarte tehnice care specifică suport îmbunătățit pentru procesarea încorporată, tipuri de date de caractere suplimentare ( suport Unicode ) și funcții de bibliotecă cu verificare a limitelor îmbunătățită . Lucrările continuă la rapoartele tehnice care se referă la virgula mobilă zecimală , funcții speciale matematice suplimentare și funcții suplimentare de alocare a memoriei dinamice . Comitetele de standarde C și C ++ au colaborat la specificații pentru programarea cu fir .

Următoarea revizuire a standardului C, C11 , a fost ratificată în 2011. Comitetul pentru standarde C a adoptat orientări care limitează adoptarea de noi caracteristici care nu au fost testate de implementările existente. S-au depus multe eforturi în dezvoltarea unui model de memorie , pentru a clarifica punctele de secvență și pentru a sprijini programarea cu fir .

Vezi si

Referințe

Lecturi suplimentare

linkuri externe

Precedat de
C89 / C90 / "ANSI C"
Standarde de limbă C Succesat de
C11