C99 - C99
Revisões de linguagem C |
---|
C99 (anteriormente conhecido como C9X ) é um nome informal para ISO / IEC 9899: 1999 , uma versão anterior do padrão de linguagem de programação C. Ele estende a versão anterior ( C90 ) com novos recursos para a linguagem e a biblioteca padrão e ajuda as implementações a fazer melhor uso do hardware de computador disponível, como aritmética de ponto flutuante IEEE 754-1985 e tecnologia de compilador. A versão C11 do padrão da linguagem de programação C, publicada em 2011, substitui o C99.
História
Depois que o ANSI produziu o padrão oficial para a linguagem de programação C em 1989, que se tornou um padrão internacional em 1990, a especificação da linguagem C permaneceu relativamente estática por algum tempo, enquanto o C ++ continuou a evoluir, principalmente durante seu próprio esforço de padronização. A Emenda Normativa 1 criou um novo padrão para C em 1995, mas apenas para corrigir alguns detalhes do padrão de 1989 e adicionar um suporte mais amplo para conjuntos de caracteres internacionais. A norma passou por uma revisão adicional no final da década de 1990, levando à publicação da ISO / IEC 9899: 1999 em 1999, que foi adotada como uma norma ANSI em maio de 2000. A linguagem definida por essa versão da norma é comumente referida como " C99 ". O padrão internacional C é mantido pelo grupo de trabalho ISO / IEC JTC1 / SC22 / WG14.
Projeto
O C99 é, na maior parte, compatível com versões anteriores do C89, mas é mais rígido em alguns aspectos.
Em particular, uma declaração que carece de um especificador de tipo não é mais int
assumida implicitamente. O comitê de padrões C decidiu que era mais valioso para os compiladores diagnosticar a omissão inadvertida do especificador de tipo do que processar silenciosamente o código legado que dependia do implícito int
. Na prática, é provável que os compiladores exibam um aviso e, em seguida, presumam int
e continuem a traduzir o programa.
O C99 introduziu vários novos recursos, muitos dos quais já haviam sido implementados como extensões em vários compiladores:
- funções inline
- declarações e código misturados: a declaração de variável não está mais restrita ao escopo do arquivo ou ao início de uma instrução composta (bloco), facilitando o formulário de atribuição única estática
- vários novos tipos de dados , incluindo
long long int
tipos de inteiros estendidos opcionais, um tipo de dados booleano explícito e umcomplex
tipo para representar números complexos - matrizes de comprimento variável (embora posteriormente relegadas em C11 a um recurso condicional que as implementações não são obrigadas a suportar)
- membros de matriz flexível
- suporte para comentários de uma linha começando com
//
, como em BCPL , C ++ e Java - novas funções de biblioteca, como
snprintf
- novos cabeçalhos , tais como , , , e
<stdbool.h>
<complex.h>
<tgmath.h>
<inttypes.h>
- matemática (macro) funções de tipo genérico, em
<tgmath.h>
que selecionar uma biblioteca de matemática função com base emfloat
,double
oulong double
argumentos, etc. - suporte aprimorado para ponto flutuante IEEE
- inicializadores designados (por exemplo, inicializar uma estrutura por nomes de campo:
struct point p = { .x = 1, .y = 2 };
) - literais compostos (por exemplo, é possível estruturas construto em chamadas de função:
function((struct x) {1, 2})
) - suporte para macros variadic (macros com um número variável de argumentos)
-
restrict
a qualificação permite uma otimização de código mais agressiva , removendo as vantagens de acesso ao array em tempo de compilação anteriormente mantidas pelo FORTRAN em relação ao ANSI C - nomes de caracteres universais, que permitem que variáveis de usuário contenham outros caracteres além do conjunto de caracteres padrão
- palavra-chave
static
em índices de matriz em declarações de parâmetro
Partes do padrão C99 estão incluídas na versão atual do padrão C ++ , incluindo tipos inteiros, cabeçalhos e funções de biblioteca. Os arrays de comprimento variável não estão entre essas partes incluídas porque a Biblioteca de modelos padrão do C ++ já inclui uma funcionalidade semelhante.
Suporte de ponto flutuante IEEE 754
Uma característica importante do C99 é seu suporte numérico e, em particular, seu suporte para acesso aos recursos do hardware de ponto flutuante IEEE 754-1985 (também conhecido como IEC 60559) presente na grande maioria dos processadores modernos (definido no "Anexo F Aritmética de ponto flutuante IEC 60559 "). Plataformas sem hardware IEEE 754 também podem implementá-lo em software.
Em plataformas com ponto flutuante IEEE 754:
-
float
é definido como precisão única IEEE 754 ,double
é definido como precisão dupla elong double
é definido como precisão estendida IEEE 754 (por exemplo, precisão estendida dupla Intel de 80 bits em plataformas x86 ou x86-64 ) ou alguma forma de precisão quádrupla quando disponível; caso contrário, é precisão dupla. - As quatro operações aritméticas e a raiz quadrada são arredondadas corretamente conforme definido pelo IEEE 754.
FLT_EVAL_METHOD flutuador Duplo longo duplo 0 flutuador Duplo longo duplo 1 Duplo Duplo longo duplo 2 longo duplo longo duplo longo duplo - A avaliação da expressão é definida para ser realizada em um dos três métodos bem definidos, indicando se as variáveis de ponto flutuante são primeiro promovidas para um formato mais preciso nas expressões:
FLT_EVAL_METHOD == 2
indica que todos os cálculos intermediários internos são realizados por padrão em alta precisão (duplo longo) onde disponível (por exemplo, 80 bit duplo estendido ),FLT_EVAL_METHOD == 1
executa todas as expressões intermediárias internas em precisão dupla (a menos que um operando seja duplo longo), enquantoFLT_EVAL_METHOD == 0
especifica que cada operação é avaliada apenas na precisão do operando mais amplo de cada operador. O tipo de resultado intermediário para operandos de uma determinada precisão está resumido na tabela adjacente.
FLT_EVAL_METHOD == 2
tende a limitar o risco de erros de arredondamento que afetam expressões numericamente instáveis (consulte a lógica do projeto IEEE 754 ) e é o método padrão projetado para hardware x87 , mas produz um comportamento não intuitivo para o usuário incauto; FLT_EVAL_METHOD == 1
era o método de avaliação padrão originalmente usado em K&R C , que promovia todos os floats a dobrar em expressões; e FLT_EVAL_METHOD == 0
também é comumente usado e especifica uma "avaliação do tipo" estrita dos operandos. (Para gcc , FLT_EVAL_METHOD == 2
é o padrão em x86 de 32 bits e FLT_EVAL_METHOD == 0
é o padrão em x86-64 de 64 bits, mas FLT_EVAL_METHOD == 2
pode ser especificado em x86-64 com a opção -mfpmath = 387.) Antes do C99, os compiladores podiam arredondar os resultados intermediários de maneira inconsistente, especialmente ao usar hardware de ponto flutuante x87 , levando a um comportamento específico do compilador; tais inconsistências não são permitidas em compiladores em conformidade com C99 (anexo F).
Exemplo
O exemplo de código C99 anotado a seguir para calcular uma função de fração contínua demonstra os principais recursos:
#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;
}
Notas de rodapé:
- Ajuntar com:
gcc -std=c99 -mfpmath=387 -o test_c99_fp -lm test_c99_fp.c
- Como os sinalizadores de status IEEE 754 são manipulados nesta função, este # pragma é necessário para evitar que o compilador reorganize incorretamente esses testes durante a otimização. (Os pragmas são geralmente definidos pela implementação, mas aqueles prefixados com
STDC
são definidos no padrão C.) - C99 define um número limitado de métodos de avaliação de expressão: o modo de compilação atual pode ser verificado para garantir que atenda aos pressupostos sob os quais o código foi escrito.
- Os valores especiais, como NaN e infinito positivo ou negativo, podem ser testados e definidos.
-
long double
é definido como IEEE 754 duplo estendido ou precisão quádrupla, se disponível. Usar uma precisão maior do que o necessário para cálculos intermediários pode minimizar o erro de arredondamento (o typedefdouble_t
pode ser usado para código que é portátil em todos osFLT_EVAL_METHOD
s). - A principal função a ser avaliada. Embora pareça que alguns argumentos para esta fração contínua, por exemplo, 3,0, levariam a um erro de divisão por zero, na verdade a função é bem definida em 3,0 e a divisão por 0 simplesmente retornará um + infinito que, então, corretamente levam a um resultado finito: o IEEE 754 é definido para não interceptar tais exceções por padrão e é projetado de forma que muitas vezes possam ser ignoradas, como neste caso. (Se
FLT_EVAL_METHOD
for definido como 2, todos os cálculos internos, incluindo constantes, serão realizados em precisão dupla longa; seFLT_EVAL_METHOD
for definido como 0, é necessário cuidado adicional para garantir isso, incluindo possíveis conversões adicionais e especificação explícita de constantes como longa dupla.) - Como o sinalizador divisão por zero elevado não é um erro neste caso, ele pode simplesmente ser descartado para limpar o sinalizador para uso por código posterior.
- Em alguns casos, outras exceções podem ser consideradas como um erro, como estouro (embora possa de fato ser mostrado que isso não pode ocorrer neste caso).
-
__STDC_IEC_559__
deve ser definido apenas se o "Anexo F IEC 60559 aritmética de ponto flutuante" for totalmente implementado pelo compilador e pela biblioteca C (os usuários devem estar cientes de que essa macro é algumas vezes definida, mas não deveria). - O modo de arredondamento padrão é arredondado para o mais próximo (com a regra de arredondamento uniforme nos casos intermediários) para IEEE 754, mas definir explicitamente o modo de arredondamento para + e - infinito (definindo
TEST_NUMERIC_STABILITY_UP
etc. neste exemplo, durante a depuração) pode ser usado para diagnosticar instabilidade numérica. Este método pode ser usado mesmo se fizercompute_fn()
parte de uma biblioteca binária compilada separadamente. Mas dependendo da função, as instabilidades numéricas nem sempre podem ser detectadas.
Detecção de versão
Uma macro padrão __STDC_VERSION__
é definida com valor 199901L
para indicar que o suporte C99 está disponível. Tal como acontece com a __STDC__
macro para C90, __STDC_VERSION__
pode ser usado para escrever código que será compilado de forma diferente para compiladores C90 e C99, como neste exemplo que garante que inline
está disponível em ambos os casos (substituindo-o por static
em C90 para evitar erros de vinculador).
#if __STDC_VERSION__ >= 199901L
/* "inline" is a keyword */
#else
# define inline static
#endif
Implementações
A maioria dos compiladores C fornece suporte para pelo menos alguns dos recursos introduzidos no C99.
Historicamente, a Microsoft tem sido lenta na implementação de novos recursos C em suas ferramentas Visual C ++ , em vez de se concentrar principalmente no desenvolvimento de suporte nos padrões C ++. No entanto, com a introdução do Visual C ++ 2013, a Microsoft implementou um subconjunto limitado do C99, que foi expandido no Visual C ++ 2015.
Compilador | Nível de suporte | Detalhes de compatibilidade C99 |
---|---|---|
Acorn C / C ++ | Parcial | A documentação oficial afirma que "a maioria" dos recursos do compilador são suportados, junto com "algumas" funções da biblioteca. |
Pacote de compilador AMD x86 Open64 | Majoritariamente | Possui suporte C99 igual ao do GCC. |
cc65 | Parcial | O suporte total para C89 e C99 não foi implementado, em parte devido às limitações da plataforma ( MOS Technology 6502 ). Não há suporte planejado para alguns tipos C99 como _Complex e inteiros de 64 bits (long long). |
CH | Parcial | Suporta os principais recursos do C99. |
Clang | Majoritariamente | Suporta todos os recursos, exceto pragmas de ponto flutuante C99. |
CompCert | Majoritariamente | Um compilador certificado, formalmente comprovado como correto. Suporta todos os recursos, exceto números complexos C99 e VLA, e restrições menores em declarações de switch (sem dispositivo de Duff ). |
cparser | Cheio | Suporta recursos C99. |
C ++ Builder | Apenas no modo de 64 bits, já que o último é CLang fork |
|
Compilador Digital Mars C / C ++ | Parcial | Não tem suporte para alguns recursos, como < tgmath.h > e _Pragma. |
GCC | Majoritariamente | Em julho de 2021, os pragmas padrão e o suporte de ponto flutuante IEEE 754 / IEC 60559 estavam ausentes no GCC da linha principal. Além disso, alguns recursos (como tipos inteiros estendidos e novas funções de biblioteca) devem ser fornecidos pela biblioteca padrão C e estão fora do escopo do GCC. As versões 4.6 e 4.7 do GCC também fornecem o mesmo nível de conformidade. Suporte parcial ao IEEE 754, mesmo quando o hardware é compatível: algumas opções do compilador podem ser necessárias para evitar otimizações incorretas (por exemplo, -std=c99 e -fsignaling-nans ), mas o suporte completo dos modos de arredondamento direcionado está ausente, mesmo quando -frounding-math é usado.
|
Software Green Hills | Cheio | |
IBM C para AIX, V6 e XL C / C ++ V11.1 para AIX | Cheio | |
Logiscope IBM Rational | Cheio | Até o Logiscope 6.3, apenas as construções básicas do C99 eram suportadas. C99 é oficialmente compatível com Logiscope 6.4 e versões posteriores. |
The Portland Group PGI C / C ++ | Cheio | |
IAR Systems Embedded Workbench |
Majoritariamente | Não suporta UCN (nomes de caracteres universais). Compilador para destinos integrados, como ARM, Coldfire, MSP430, AVR, AVR32, 8051, ... Sem destinos x86. |
Compilador Intel C ++ | Majoritariamente |
|
Microsoft Visual C ++ | Parcial | Visual C ++ 2012 e anterior não oferece suporte a C99. Visual C ++ 2013 implementa um subconjunto limitado de C99 necessário para compilar projetos populares de código aberto. Visual C ++ 2015 implementa a biblioteca padrão C99, com exceção de quaisquer recursos de biblioteca que dependem de recursos do compilador ainda não suportados pelo compilador (por exemplo, < tgmath.h > não foi implementado). O Visual C ++ 2019 (16.6) adiciona suporte opcional para um pré-processador compatível com C99. |
Open Watcom | Parcial | Implementa as partes mais comumente usadas do padrão. No entanto, eles são ativados apenas por meio da opção de linha de comando não documentada "-za99". Três recursos C99 foram agrupados como extensões C90 desde pré-v1.0: comentários de estilo C ++ (//), membros de matriz flexível, vírgula final permitida na declaração de enum. |
Pelles C | Cheio | Suporta todos os recursos do C99. |
Compilador C portátil | Parcial | Trabalhando para se tornar compatível com C99. |
Sun Studio | Cheio | |
O Amsterdam Compiler Kit | Não | Um frontend C99 está atualmente sob investigação. |
Compilador Tiny C | Parcial | Não suporta números complexos. Matrizes de comprimento variável são suportadas, mas não como argumentos em funções. Os desenvolvedores afirmam que "o TCC está caminhando para a conformidade total com o ISOC99". |
vbcc | Parcial |
Trabalho futuro
Desde a ratificação do padrão C de 1999, o grupo de trabalho de padrões preparou relatórios técnicos especificando suporte aprimorado para processamento integrado, tipos de dados de caracteres adicionais ( suporte Unicode ) e funções de biblioteca com verificação aprimorada de limites . O trabalho continua em relatórios técnicos que tratam de ponto flutuante decimal , funções matemáticas especiais adicionais e funções adicionais de alocação de memória dinâmica . Os comitês de padrões C e C ++ têm colaborado nas especificações de programação encadeada .
A próxima revisão do padrão C, C11 , foi ratificada em 2011. O comitê de padrões C adotou diretrizes que limitaram a adoção de novos recursos que não foram testados pelas implementações existentes. Muito esforço foi dedicado ao desenvolvimento de um modelo de memória , a fim de esclarecer pontos de sequência e oferecer suporte à programação encadeada .
Veja também
- C ++ 20 , C ++ 17 , C ++ 14 , C ++ 11 , C ++ 03 , C ++ 98 , versões do padrão de linguagem de programação C ++
- Compatibilidade de C e C ++
- Relatório Técnico C ++ 1
- Ponto flutuante , para uma discussão mais aprofundada sobre o uso de hardware IEEE 754
Referências
Leitura adicional
- Cheng, Harry (1 de março de 2002). "C99 e computação numérica" . Diário do Dr. Dobb .
- Seebach, Peter (24 de março de 2004). "Desenvolvimento de código aberto usando C99" . developerWorks . IBM .
- "Versão final da norma C99 com corrigenda TC1, TC2 e TC3 incluída, formatada como um rascunho" (PDF) . (3,61 MB)
- Justificativa para o Padrão Internacional - Linguagens de Programação - Revisão C 5.10 , abril de 2003, Justificativa para C99