C99 - C99
C revizuiri ale limbajului |
---|
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
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 int
implicită. 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 uncomplex
tip 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 bazafloat
,double
saulong double
argumente, 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)
-
restrict
calificarea 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:
-
float
este definit ca o singură precizie IEEE 754 ,double
este definit ca o precizie dublă șilong double
este 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 == 2
indică 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 == 1
efectuează toate expresiile intermediare interne cu precizie dublă (cu excepția cazului în care un operand este dublu lung), în timp ceFLT_EVAL_METHOD == 0
specifică 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 == 2
tinde 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 == 1
a 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 == 0
este, de asemenea, utilizat în mod obișnuit și specifică o „evaluare la tip” strictă a operanzilor. (Pentru gcc , FLT_EVAL_METHOD == 2
este implicit pe 32 biți x86 și FLT_EVAL_METHOD == 0
este implicit pe 64 biți x86-64, dar FLT_EVAL_METHOD == 2
poate 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:
- Compilați cu:
gcc -std=c99 -mfpmath=387 -o test_c99_fp -lm test_c99_fp.c
- 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
STDC
sunt definite în standardul C.) - 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.
- Valorile speciale precum NaN și infinitul pozitiv sau negativ pot fi testate și setate.
-
long double
este 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 typedefdouble_t
poate fi utilizat pentru cod care este portabil sub toateFLT_EVAL_METHOD
s). - 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_METHOD
este definit ca 2, atunci toate calculele interne, inclusiv constantele, vor fi efectuate cu o precizie dublă lungă; dacăFLT_EVAL_METHOD
este 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ă.) - Î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.
- Î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).
-
__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). - 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_UP
etc. î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 199901L
pentru 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ă inline
este 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.
Compilator | Nivelul de sprijin | Detalii de compatibilitate C99 |
---|---|---|
Acorn C / C ++ | Parțial | Documentația oficială precizează că „majoritatea” caracteristicilor compilatorului sunt acceptate, împreună cu „unele” funcții ale bibliotecii. |
AMD x86 Open64 Compiler Suite | Mai ales | Are suport C99 egal cu cel al GCC. |
cc65 | Parțial | Suportul complet C89 și C99 nu este implementat, parțial din cauza limitărilor platformei ( tehnologia MOS 6502 ). Nu există suport planificat pentru unele tipuri C99, cum ar fi _Complex și numere întregi pe 64 de biți (lung lung). |
Ch | Parțial | Suportă caracteristici majore C99. |
Zăngăni | Mai ales | Suportă toate caracteristicile, cu excepția pragmelor cu virgulă mobilă C99. |
CompCert | Mai ales | Un compilator certificat, s-a dovedit formal corect. Suportă toate caracteristicile, cu excepția numerelor complexe C99 și VLA, și restricții minore asupra declarațiilor de comutare (fără dispozitiv Duff ). |
cparser | Deplin | Suportă funcții C99. |
C ++ Builder | Numai în modul pe 64 de biți, deoarece acesta este furca CLang |
|
Compilator digital Mars C / C ++ | Parțial | Nu are suport pentru unele caracteristici, cum ar fi < tgmath.h > și _Pragma. |
GCC | Mai ales | Începând cu iulie 2021, pragmele standard și suportul cu virgulă mobilă IEEE 754 / IEC 60559 lipsesc în GCC principal. În plus, unele caracteristici (cum ar fi tipurile de numere întregi extinse și noile funcții de bibliotecă) trebuie furnizate de biblioteca standard C și nu intră în domeniul de aplicare pentru GCC. Versiunile 4.6 și 4.7 ale GCC oferă, de asemenea, același nivel de conformitate. Suport parțial IEEE 754, chiar și atunci când hardware-ul este compatibil: unele opțiuni ale compilatorului pot fi necesare pentru a evita optimizări incorecte (de exemplu, -std=c99 și -fsignaling-nans ), dar suportul complet al modurilor de rotunjire direcționată lipsește chiar și atunci când -frounding-math este utilizat.
|
Software-ul Green Hills | Deplin | |
IBM C pentru AIX, V6 și XL C / C ++ V11.1 pentru AIX | Deplin | |
IBM Rational logiscope | Deplin | Până la Logiscope 6.3, erau acceptate doar construcțiile de bază ale C99. C99 este acceptat oficial în Logiscope 6.4 și versiunile ulterioare. |
Grupul Portland PGI C / C ++ | Deplin | |
IAR Systems Embedded Workbench |
Mai ales | Nu acceptă UCN (nume de caractere universale). Compilator pentru ținte încorporate, cum ar fi ARM, Coldfire, MSP430, AVR, AVR32, 8051, ... Fără ținte x86. |
Compilator Intel C ++ | Mai ales |
|
Microsoft Visual C ++ | Parțial | Visual C ++ 2012 și versiunile anterioare nu au acceptat C99. Visual C ++ 2013 implementează un subset limitat de C99 necesar pentru a compila proiecte open-source populare. Visual C ++ 2015 implementează biblioteca standard C99, cu excepția oricăror caracteristici de bibliotecă care depind de caracteristicile compilatorului care nu sunt încă acceptate de compilator (de exemplu, < tgmath.h > nu este implementat). Visual C ++ 2019 (16.6) adaugă suport opt-in pentru un preprocesor conform C99. |
Deschideți Watcom | Parțial | Implementează cele mai utilizate părți ale standardului. Cu toate acestea, acestea sunt activate numai prin comutatorul de linie de comandă nedocumentat „-za99”. Trei caracteristici C99 au fost incluse ca extensii C90 începând cu versiunea anterioară v1.0: comentarii în stil C ++ (//), membri de matrice flexibili, virgulă finală permisă în declarația enum. |
Pelles C | Deplin | Suportă toate caracteristicile C99. |
Compilator C portabil | Parțial | Lucrăm pentru a deveni compatibil C99. |
Sun Studio | Deplin | |
Compiler Kit Amsterdam | Nu | Un frontend C99 este în prezent în curs de investigare. |
Compilator Tiny C | Parțial | Nu acceptă numere complexe. Tablourile de lungime variabilă sunt acceptate, dar nu ca argumente în funcții. Dezvoltatorii declară că „TCC se îndreaptă spre conformitatea totală ISOC99”. |
vbcc | Parțial |
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
- C ++ 20 , C ++ 17 , C ++ 14 , C ++ 11 , C ++ 03 , C ++ 98 , versiuni ale standardului de limbaj de programare C ++
- Compatibilitatea C și C ++
- Raport tehnic C ++ 1
- Punct plutitor , pentru discuții suplimentare despre utilizarea hardware-ului IEEE 754
Referințe
Lecturi suplimentare
- Cheng, Harry (1 martie 2002). "C99 și calcul numeric" . Jurnalul Dr. Dobb .
- Seebach, Peter (24 martie 2004). "Dezvoltare open source folosind C99" . developerWorks . IBM .
- „Versiunea finală a standardului C99 cu rectificările TC1, TC2 și TC3 incluse, formatată ca schiță” (PDF) . (3,61 MB)
- Justificarea standardului internațional - Limbaje de programare - Revizia C 5.10 , aprilie-2003, Justificarea pentru C99