C99 - C99
Revize jazyka C. |
---|
C99 (dříve známý jako C9X ) je neformální název pro ISO/IEC 9899: 1999 , předchozí verzi standardu programovacího jazyka C. Rozšiřuje předchozí verzi ( C90 ) o nové funkce pro jazyk a standardní knihovnu a pomáhá implementacím lépe využívat dostupný počítačový hardware, jako je aritmetika s plovoucí desetinnou čárkou IEEE 754-1985 a technologie kompilátoru. Verze C11 standardu programovacího jazyka C, publikovaná v roce 2011, nahrazuje C99.
Dějiny
Poté, co ANSI v roce 1989 vytvořilo oficiální standard pro programovací jazyk C, který se v roce 1990 stal mezinárodním standardem, zůstala specifikace jazyka C po určitou dobu relativně statická, zatímco C ++ se nadále vyvíjel, převážně během vlastního úsilí o standardizaci. Normativní dodatek 1 vytvořil nový standard pro C v roce 1995, ale pouze za účelem opravy některých podrobností standardu z roku 1989 a přidání rozsáhlejší podpory pro mezinárodní znakové sady. Norma prošla další revizí na konci devadesátých let, což vedlo k vydání ISO/IEC 9899: 1999 v roce 1999, která byla přijata jako norma ANSI v květnu 2000. Jazyk definovaný touto verzí normy se běžně označuje jako „ C99 ". Mezinárodní normu C udržuje pracovní skupina ISO/IEC JTC1/SC22 /WG14.
Design
C99 je z větší části zpětně kompatibilní s C89, ale v některých ohledech je přísnější.
Zejména deklarace, která postrádá specifikátor typu, již int
implicitně nepředpokládala. Výbor pro standardy C rozhodl, že pro kompilátory má větší hodnotu diagnostikovat neúmyslné vynechání specifikátoru typu, než bezobslužně zpracovávat starší kód, který spoléhá na implicitní int
. V praxi kompilátory pravděpodobně zobrazí varování, poté předpokládají int
a pokračují v překládání programu.
C99 představil několik nových funkcí, z nichž mnohé již byly implementovány jako rozšíření v několika kompilátorech:
- vložené funkce
- smíšené deklarace a kód: deklarace proměnné již není omezena na rozsah souboru nebo začátek složeného příkazu (bloku), což usnadňuje statický jednoduchý formulář přiřazení
- několik nových datových typů , včetně
long long int
volitelných rozšířených celočíselných typů, explicitní booleovský datový typ acomplex
typ reprezentující komplexní čísla - pole s proměnnou délkou (i když následně zařazena v C11 do podmíněné funkce, kterou implementace nemusí podporovat)
- flexibilní členy pole
- podpora pro jednořádkové komentáře začínající
//
, jako v BCPL , C ++ a Java - nové funkce knihovny, jako např
snprintf
- nová záhlaví , jako například , , a
<stdbool.h>
<complex.h>
<tgmath.h>
<inttypes.h>
- typ-generic math (makro) funkce, v
<tgmath.h>
, kteří vybírají si matematická knihovna funkce založené nafloat
,double
nebolong double
argumenty, atd. - vylepšená podpora pro IEEE s plovoucí desetinnou čárkou
- určené Inicializátory (například inicializaci strukturu názvy polí:
struct point p = { .x = 1, .y = 2 };
) - sloučenina Literály (například, že je možné konstruovat struktur v volání funkce:
function((struct x) {1, 2})
) - podpora variadických maker (makra s proměnným počtem argumentů)
-
restrict
kvalifikace umožňuje agresivnější optimalizaci kódu a odstraňuje výhody přístupu k poli v době kompilace, které dříve vlastnil FORTRAN oproti ANSI C. - univerzální názvy znaků, která umožňuje, aby uživatelské proměnné obsahovaly jiné znaky než standardní znakovou sadu
- klíčové slovo
static
v indexech pole v deklaracích parametrů
Části standardu C99 jsou součástí aktuální verze standardu C ++ , včetně celočíselných typů, záhlaví a funkcí knihovny. Pole s proměnnou délkou mezi tyto zahrnuté části nepatří, protože standardní knihovna šablon C ++ již obsahuje podobné funkce.
Podpora IEEE 754 s plovoucí desetinnou čárkou
Hlavní vlastností C99 je numerická podpora, a zejména podpora přístupu k funkcím hardwaru s plovoucí desetinnou čárkou IEEE 754-1985 (také známého jako IEC 60559) přítomného v drtivé většině moderních procesorů (definováno v "Příloze F" Aritmetika s pohyblivou řádovou čárkou podle IEC 60559 “). Platformy bez hardwaru IEEE 754 jej mohou také implementovat do softwaru.
Na platformách s plovoucí desetinnou čárkou IEEE 754:
-
float
je definován jako jednoduchá přesnost IEEE 754 ,double
je definován jako dvojitá přesnost along double
je definován jako rozšířená přesnost IEEE 754 (např. 80bitová dvojitá rozšířená přesnost Intel na platformách x86 nebo x86-64 ) nebo nějaká forma čtyřnásobné přesnosti, je -li k dispozici; jinak je to dvojnásobná přesnost. - Čtyři aritmetické operace a odmocnina jsou správně zaokrouhleny podle definice IEEE 754.
FLT_EVAL_METHOD plovák dvojnásobek dlouhý dvojník 0 plovák dvojnásobek dlouhý dvojník 1 dvojnásobek dvojnásobek dlouhý dvojník 2 dlouhý dvojník dlouhý dvojník dlouhý dvojník - Vyhodnocení výrazu je definováno tak, aby bylo provedeno jednou ze tří dobře definovaných metod, což indikuje, zda jsou proměnné s plovoucí desetinnou čárkou ve výrazech nejprve povýšeny na přesnější formát:
FLT_EVAL_METHOD == 2
označuje, že všechny interní mezilehlé výpočty jsou standardně prováděny s vysokou přesností (dlouhé dvojité) pokud je k dispozici (např. 80bitový dvojitě rozšířený ),FLT_EVAL_METHOD == 1
provede všechny interní mezilehlé výrazy s dvojitou přesností (pokud není operand dlouhý dvojitý), přičemžFLT_EVAL_METHOD == 0
určuje, že každá operace je hodnocena pouze s přesností nejširšího operandu každého operátora. Typ mezilehlého výsledku pro operandy dané přesnosti jsou shrnuty v sousední tabulce.
FLT_EVAL_METHOD == 2
má tendenci omezovat riziko zaokrouhlování chyb ovlivňujících numericky nestabilní výrazy (viz odůvodnění návrhu IEEE 754 ) a je navrženou výchozí metodou pro hardware x87 , ale poskytuje neintuitivní chování pro neopatrného uživatele; FLT_EVAL_METHOD == 1
byla výchozí metoda hodnocení původně používaná v K&R C , která propagovala všechny plováky na zdvojnásobení výrazů; a FLT_EVAL_METHOD == 0
také se běžně používá a určuje přísné "vyhodnotit podle typu" operandů. (Pro gcc , FLT_EVAL_METHOD == 2
je výchozí na 32 bit x86, a FLT_EVAL_METHOD == 0
je výchozí na 64 bit x86-64, ale FLT_EVAL_METHOD == 2
může to být uvedeno na x86-64 s možností -mfpmath = 387). Před C99, překladače mohl projet mezivýsledky nekonzistentně, a to zejména při použití hardwaru s plovoucí desetinnou čárkou x87 , což vede k chování konkrétního kompilátoru; takové nesrovnalosti nejsou povoleny u překladačů vyhovujících C99 (příloha F).
Příklad
Následující komentovaný příklad kódu C99 pro výpočet funkce pokračování zlomku ukazuje hlavní funkce:
#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;
}
Poznámky pod čarou:
- Zkompilovat s:
gcc -std=c99 -mfpmath=387 -o test_c99_fp -lm test_c99_fp.c
- Protože se v této funkci manipulují se stavovými příznaky IEEE 754, je tato #pragma potřebná, aby kompilátor při optimalizaci nesprávně nesestavil takové testy. (Pragmas jsou obvykle definovány implementací, ale ty s předponou
STDC
jsou definovány ve standardu C.) - C99 definuje omezený počet metod hodnocení výrazu: aktuální režim kompilace lze zkontrolovat, aby se zajistilo, že splňuje předpoklady, pod které byl kód napsán.
- Lze testovat a nastavovat speciální hodnoty, jako je NaN a pozitivní nebo negativní nekonečno.
-
long double
je definován jako IEEE 754 s dvojnásobně rozšířenou nebo čtyřnásobnou přesností, je -li k dispozici. Použití vyšší přesnosti, než je požadováno u přechodných výpočtů, může minimalizovat chyby zaokrouhlení ( typedefdouble_t
lze použít pro kód, který je přenosný pod všemiFLT_EVAL_METHOD
s). - Hlavní funkce, která se má vyhodnotit. Ačkoli se zdá, že některé argumenty k tomuto pokračujícímu zlomku, např. 3,0, by vedly k chybě dělení nulou, ve skutečnosti je funkce dobře definována na 3,0 a dělení 0 jednoduše vrátí +nekonečno, které pak správně vést ke konečnému výsledku: IEEE 754 je definován tak, aby ve výchozím nastavení nezachytával takové výjimky, a je navržen tak, aby je bylo možné velmi často ignorovat, jako v tomto případě. (Pokud
FLT_EVAL_METHOD
je definován jako 2, pak budou všechny interní výpočty včetně konstant prováděny s dlouhou dvojitou přesností; pokudFLT_EVAL_METHOD
je definováno jako 0, pak je třeba zajistit další péči, včetně případných dalších přetypování a explicitní specifikace konstant jako dlouhých dvojitých.) - Vzhledem k tomu, že zvýšený příznak dělení nulou není v tomto případě chybou, lze jej jednoduše zrušit, aby byl příznak vymazán pro použití v pozdějším kódu.
- V některých případech mohou být jiné výjimky považovány za chybu, například přetečení (i když ve skutečnosti lze ukázat, že v tomto případě k tomu nemůže dojít).
-
__STDC_IEC_559__
je definován pouze tehdy, pokud je kompilátor a knihovna C plně implementován „aritmetika s plovoucí desetinnou čárkou podle přílohy F IEC 60559“ (uživatelé by si měli být vědomi toho, že toto makro je někdy definováno, i když by nemělo být). - Výchozí režim zaokrouhlení je u IEEE 754 zaokrouhlen na nejbližší (s pravidlem rovnoměrného zaokrouhlování v půli cesty), ale lze explicitně použít režim zaokrouhlení směrem k + a - nekonečnu (definováním
TEST_NUMERIC_STABILITY_UP
atd. V tomto případě při ladění) diagnostikovat numerickou nestabilitu. Tuto metodu lze použít, i kdyžcompute_fn()
je součástí samostatně kompilované binární knihovny. Ale v závislosti na funkci nelze vždy zjistit numerické nestability.
Detekce verzí
Standardní makro __STDC_VERSION__
je definováno s hodnotou, 199901L
která označuje, že je k dispozici podpora C99. Stejně jako u __STDC__
makra pro C90 __STDC_VERSION__
lze použít k zápisu kódu, který se bude kompilovat odlišně pro kompilátory C90 a C99, jako v tomto příkladu, který zajišťuje, že inline
je k dispozici v obou případech (jeho nahrazením static
v C90, aby se předešlo chybám linkeru).
#if __STDC_VERSION__ >= 199901L
/* "inline" is a keyword */
#else
# define inline static
#endif
Implementace
Většina kompilátorů C poskytuje podporu alespoň pro některé funkce uvedené v C99.
Microsoft historicky pomalu implementoval nové funkce C do svých nástrojů Visual C ++ , místo toho se soustředil hlavně na podporu vývoje standardů C ++. Nicméně se zavedením Visual C ++ 2013 Microsoft implementoval omezenou podmnožinu C99, která byla rozšířena v Visual C ++ 2015.
Překladač | Úroveň podpory | Podrobnosti o kompatibilitě C99 |
---|---|---|
Žalud C/C ++ | Částečný | Oficiální dokumentace uvádí, že „většina“ funkcí kompilátoru je podporována spolu s „některými“ funkcemi knihovny. |
Sada kompilátorů AMD x86 Open64 | Většinou | Má podporu C99 stejnou jako podpora GCC. |
cc65 | Částečný | Plná podpora C89 a C99 není implementována, částečně kvůli omezením platformy ( MOS Technology 6502 ). U některých typů C99, jako je _Complex a 64bitová celá čísla (dlouhá dlouhá), není plánována žádná podpora. |
Ch | Částečný | Podporuje hlavní funkce C99. |
Zvonit | Většinou | Podporuje všechny funkce kromě pragmat C99 s pohyblivou řádovou čárkou. |
CompCert | Většinou | Certifikovaný překladač se formálně ukázal jako správný. Podporuje všechny funkce kromě komplexních čísel C99 a VLA a drobných omezení v prohlášeních přepínačů (žádné zařízení Duff ). |
cparser | Úplný | Podporuje funkce C99. |
C ++ Builder | Pouze v 64bitovém režimu, protože je to vidlice CLang |
|
Kompilátor Digital Mars C/C ++ | Částečný | Chybí podpora pro některé funkce, například < tgmath.h > a _Pragma. |
GCC | Většinou | Jak července 2021, standardní pragmas a podpora IEEE 754/IEC 60559 s plovoucí desetinnou čárkou chybí v hlavní řadě GCC. Kromě toho některé funkce (například rozšířené celočíselné typy a nové funkce knihovny) musí poskytovat standardní knihovna C a jsou mimo rozsah GCC. Verze 4.6 a 4.7 GCC také poskytují stejnou úroveň shody. Částečná podpora IEEE 754, i když je hardware kompatibilní: Aby se předešlo nesprávným optimalizacím (např. -std=c99 A -fsignaling-nans ), mohou být potřeba některé možnosti kompilátoru , ale plná podpora režimů řízeného zaokrouhlování chybí, i když -frounding-math je použita.
|
Software Green Hills | Úplný | |
IBM C pro AIX, V6 a XL C/C ++ V11.1 pro AIX | Úplný | |
IBM Rational logiscope | Úplný | Až do Logiscope 6.3 byly podporovány pouze základní konstrukce C99. C99 je oficiálně podporován v Logiscope 6.4 a novějších verzích. |
Portlandská skupina CHZO C/C ++ | Úplný | |
Integrovaný pracovní stůl IAR Systems |
Většinou | Nepodporuje UCN (univerzální názvy znaků). Kompilátor pro vložené cíle, jako jsou ARM, Coldfire, MSP430, AVR, AVR32, 8051, ... Žádné cíle x86. |
Kompilátor Intel C ++ | Většinou |
|
Microsoft Visual C ++ | Částečný | Visual C ++ 2012 a starší nepodporovaly C99. Visual C ++ 2013 implementuje omezenou podmnožinu C99 potřebnou ke kompilaci populárních open-source projektů. Visual C ++ 2015 implementuje standardní knihovnu C99, s výjimkou všech funkcí knihovny, které závisí na funkcích kompilátoru, které kompilátor ještě nepodporuje (například < tgmath.h > není implementováno). Visual C ++ 2019 (16.6) přidává podporu opt-in pro preprocesor kompatibilní s C99. |
Otevřete Watcom | Částečný | Implementuje nejčastěji používané části standardu. Jsou však povoleny pouze prostřednictvím nezdokumentovaného přepínače příkazového řádku "-za99". Od verze před verzí 1.0 byly přidány tři funkce C99 jako rozšíření C90: komentáře ve stylu C ++ (//), flexibilní členové pole, koncová čárka povolená v deklaraci výčtu. |
Pelles C | Úplný | Podporuje všechny funkce C99. |
Přenosný kompilátor C. | Částečný | Práce na dosažení souladu s C99. |
Sluneční studio | Úplný | |
Amsterdam kompilátoru Kit | Ne | Frontend C99 je v současné době předmětem vyšetřování. |
Kompilátor Tiny C. | Částečný | Nepodporuje složitá čísla. Pole s proměnnou délkou jsou podporována, ale ne jako argumenty ve funkcích. Vývojáři uvádějí, že „TCC směřuje k plné shodě s ISOC99“. |
vbcc | Částečný |
Budoucí práce
Od ratifikace standardu 1999 C připravila pracovní skupina pro standardy technické zprávy specifikující vylepšenou podporu pro vložené zpracování, další datové typy znaků ( podpora Unicode ) a funkce knihovny s vylepšenou kontrolou hranic . Pokračují práce na technických zprávách řešících desetinnou čárku , další speciální matematické funkce a další funkce dynamické alokace paměti . Výbory pro standardy C a C ++ spolupracují na specifikacích pro programování závitů .
Další revize normy C, C11 , byla ratifikována v roce 2011. Výbor pro normy C přijal pokyny, které omezovaly přijímání nových funkcí, které nebyly testovány stávajícími implementacemi. Mnoho úsilí bylo vynaloženo na vývoj paměťového modelu , aby se vyjasnily body sekvence a aby se podporovalo programování závitů .
Viz také
- C ++ 20 , C ++ 17 , C ++ 14 , C ++ 11 , C ++ 03 , C ++ 98 , verze standardu programovacího jazyka C ++
- Kompatibilita C a C ++
- Technická zpráva C ++ 1
- Floating point , pro další diskusi o využití hardwaru IEEE 754
Reference
Další čtení
- Cheng, Harry (1. března 2002). „C99 a numerické výpočty“ . Dr. Dobb's Journal .
- Seebach, Peter (24. března 2004). „Vývoj open source pomocí C99“ . developerWorks . IBM .
- „Konečná verze standardu C99 s opravami TC1, TC2 a TC3 je součástí, naformátovaná jako koncept“ (PDF) . (3,61 MB)
- Odůvodnění mezinárodní normy-programovací jazyky-C Revize 5.10 , duben-2003, Odůvodnění pro C99