C99 - C99

Capa do documento de padrões C99

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

1999 ISO C.pdf

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 intassumida 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 inte 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:

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 e long 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 == 2indica 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 == 1executa todas as expressões intermediárias internas em precisão dupla (a menos que um operando seja duplo longo), enquanto FLT_EVAL_METHOD == 0especifica 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 == 2tende 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 == 1era 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 == 0també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 == 2pode 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é:

  1. Ajuntar com: gcc -std=c99 -mfpmath=387 -o test_c99_fp -lm test_c99_fp.c
  2. 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 STDCsão definidos no padrão C.)
  3. 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.
  4. Os valores especiais, como NaN e infinito positivo ou negativo, podem ser testados e definidos.
  5. 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 typedef double_t pode ser usado para código que é portátil em todos os FLT_EVAL_METHODs).
  6. 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_METHODfor definido como 2, todos os cálculos internos, incluindo constantes, serão realizados em precisão dupla longa; se FLT_EVAL_METHODfor 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.)
  7. 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.
  8. 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).
  9. __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).
  10. 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_UPetc. neste exemplo, durante a depuração) pode ser usado para diagnosticar instabilidade numérica. Este método pode ser usado mesmo se fizer compute_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 199901Lpara 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 inlineestá disponível em ambos os casos (substituindo-o por staticem 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.

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

Referências

Leitura adicional

links externos

Precedido por
C89 / C90 / "ANSI C"
Padrões de linguagem C Aprovado por
C11