Algumas particularidades sintáticas de C99

C99

Frequentemente vejo alguns amigos desenvolvendo em C e sempre se deparam com algumas construções que são completamente “esquisitas”. O esquisito está entre aspas pois são construções que não são válidas em ANSI C (ou no nosso bom e velho amigo C89) e completamente válidas em C99.

 

Em artigos anteriores eu utilizei algumas construções não muito usuais, e que gosto muito: inicialização de estruturas, de vetores e compound literals. Como os compiladores ANSI C utilizados em sistemas embarcados já provém suporte ao C99, nada como explorar isso e ver como tirar mais proveito do compilador.

 

 

Inicialização de vetores

 

Em C89 a inicialização dos elementos de vetores é em ordem fixa, respeitando a ordem dos elementos no vetor. Já em C99, especificando o elemento do vetor o qual queremos inicializar, podemos inicializá-lo em qualquer ordem. Para inicializar um elemento de vetor em C99, escreva ‘[índice] =’ antes do valor do elemento, por exemplo: 

 

A construção acima é equivalente à inicialização a seguir em C89: 

 

Repare que os termos não inicializados explicitamente são inicializados com zero.

 

 

Inicialização de estruturas

 

Em C89 você pode inicializar uma estrutura assim: 

 

O detalhe aqui é que os elementos devem ser inicializados na mesma ordem que eles são listados na declaração da struct: 

 

Assim, quando declaramos uma variável do tipo struct STGpioOutputConfig, dwSYSCTL vem primeiro,  dwBase depois e assim por diante. Isso pode ser um inconveniente pois como todo código de inicialização não é alterado nunca, todo código dependente da ordem dos inicializadores pode não funcionar mais. Em C99 você pode inicializar uma estrutura especificando os nomes dos elementos da struct:

 

Esta construção não somente desacopla a ordem dos inicializadores, mas torna o código mais legível. Como benefício adicionado, os elementos não inicializados são inicializados com zero (0). Como facilidade, se durante o projeto qualquer campo for adicionado à estrutura, a sua inicialização pode ser acrescentada sem medo de que os outros elementos da estrutura tenham o valor de inicialização alterados.

 

Neste ponto vou indicar uma forma de organização de projetos que utilizo frequentemente, que é a inicialização de vetores de estruturas de tal forma a representar algum aspecto de implementação. Repare que o vetor de estruturas declarado acima, stUserLedCfg, é a representação de vários LEDs presentes em um projeto. Dependendo do tamanho do projeto pode ser um pouco difícil de lembrar qual elemento do vetor representa um dado led. Assim, sempre que possível, declaro uma enumeração que cobre a faixa de elementos do vetor e, na  inicialização, inicializo cada elemento explicitamente. Para o vetor de estrutura citado, ficaria assim:

 

Com esta construção fica muito mais fácil de organizar o código e ele se torna totalmente extensível.

 

 

Compound literals em atribuição a estruturas

 

Esta nova sintaxe de inicialização de estruturas é fabulosa, mas não ajuda em tudo. Vamos a um exemplo prático: necessitamos inicializar uma estrutura qualquer, por exemplo, a GPIO_InitTypeDef presente na STDPeripheralLib da ST. Em C89, teríamos algo assim:

 

Usando a construção de C99 chamada compound literal, você pode atribuir valores para a struct initGPIO da forma apresentada abaixo:

 

Tenha em mente que esta construção sempre emprega uma declaração anônima. Debaixo do capô, o compilador faz algo do tipo:

 

Novamente, a coisa legal aqui é que os elementos não inicializados explicitamente são inicializados com zero.

 

Com a mesma construção, é possível inicializar uma struct com zero somente com a seguinte declaração:

 

 

Compound literals com primitivas

 

Compound literals também podem ser aplicadas a primitivas. Em geral, a declaração abaixo não tem muita utilidade: 

 

Porém, devido ao compound literal estar associado a uma variável anônima, podemos usar o endereço dela:

 

Podemos aplicar isso em exemplos do tipo abaixo, que é uma construção C89:

 

A mesma construção poderia ser feita em C99 da forma mostrada abaixo:

 

 

Conclusão - C89 vs C99

 

Enquanto C99 possui alguns updates em relação ao padrão C89, é interessante habilitá-lo em seu compilador e começar a usar. O seu uso tornará as suas implementações mais legíveis e portáveis. Além disso, atente-se à documentação do seu compilador, pois podemos ter alguns ganhos de velocidade ou de uso de memória se utilizarmos compound literals e outras construções de C99.

NEWSLETTER

Receba os melhores conteúdos sobre sistemas eletrônicos embarcados, dicas, tutoriais e promoções.

Obrigado! Sua inscrição foi um sucesso.

Ops, algo deu errado. Por favor tente novamente.

Rafael Dias
Sou Bacharel em Física formado pelo Instituto de Física da USP, mestre em Engenharia Elétrica, com ênfase em materiais nanoestruturados pela Escola Politécnica da USP e também Técnico em Automação da Manufatura pela Escola SENAI Anchieta. Trabalho com desenvolvimento de software, firmware e me arrisco com eletrônica analógica para instrumentação e controle. Nos tempos livres gosto de dar uma espairecida e pedalar um pouco.

3
Deixe um comentário

avatar
 
2 Comment threads
1 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
3 Comment authors
JonnyDoinRafael DiasEduardo Gomes Recent comment authors
  Notificações  
recentes antigos mais votados
Notificar
JonnyDoin
Visitante
JonnyDoin

Dias, excelente artigo! Compound literals são um dos aspectos menos explorados do C99, e permitem construções de alto nível, com declaração no ponto-de-uso. Um dos aspectos que mais gosto em compound literals é o uso de pointers para structs como passagem de parâmetros em funções. Neste caso, o uso de compound literals permite a especificação de named parameters, similar a linguagens mais estruturadas (como ADA, por exemplo). Esta construção é C99: // SECURE_STATUS_T ecdsa_verify(ECDSA_VECTOR_T *vector, ECDSA_CMD_EVENT_T *event); SECURE_STATUS_T ret = ecdsa_verify( &(ECDSA_VECTOR_T){ .key_type = ECC_KEY_SYS_MASTER, // master public key .msg_hash = ecdsa.msg_hash, // ptr to the 32bytes sha-256 message hash .key_length = 64, // public key length for P256 .signature_length = 64, // signature length is 64 bytes .signature = ecdsa.master_sign // ptr to the signature buffer }, &(ECDSA_CMD_EVENT_T){ .object = &ecdsa, // ptr to object data .callback = ecdsa_product_verify_callback_handler… Leia mais »

Eduardo Gomes
Membro
Eduardo Gomes

Muito esclarecedor. Parabéns pelo artigo!