C Moderno

=========================================

Postado em November 24, 2024 por Paulo

C é uma linguagem que bastante antiga e com uma comunidade bastante madura, em início de sua história ocorreram bastantes mudanças, mais notavelmente do C estilo K&R para o popular ANSI C. Essa linguagem é tão universalmente conhecida que alguns até a chamam de linguagem de programação oficial do nosso planeta.

A linguagem de programação C continua evoluindo e novos recursos vem sendo adicionado com o objetivo de moderniza-la.

O C moderno é padronizado pela ISO/IEC JTC1/SC22/WG14, essa organização padroniza a linguagem desde 1990 até os dias atuais. Vamos explorar algumas das adições feitas última década até agora.

Nesse artigo vamos documentar alguns dos novos recursos que mais achei interessante e talvez mude a maneira que você programe em C.

_BitInt

_BitInt(), antes chamado de _Extint em propóstas passadas é um tipo de largura-bit arbitrário, ou seja, permite você criar números inteiros de qualquer tamanho. É análogo ao recurso da linguagem zig que permite o mesmo comportamento.

Mas quais seriam os casos de uso do _BitInt()? Imagine que você está escrevendo um sistema de conversão de strings em Base64 para strings padrão? Um caractere Base64 tem 6 bits de largura, se usarmos um char, tipo que tem 8 bits de largura para representar cada átomo de um Base64 estariamos gastando memória atoa, então um valor de tipo _BitInt(6) seria ideal para armazenar o valor desse carectere 6 bits-wide.

Ou até pode ser usado para armazenar números extremamente grandes como no exemplo abaixo.

Exemplo _BitInt:

// exemplo trabalhando com números extremamente grandes
#include <stdio.h>

int main(void) {
    _BitInt (1048576) x = ((_BitInt (1048576)) 1) << (1 << 20);

    bool is_even = x % 2 == 0;
    puts( (is_even) ? "2^(2^20) é par!" : "2^(2^20) é impar!" );
}

Esse programa produz a saída:

2^(2^20) é par!

Atualmente esse recurso está para ser amplamente implementado depois de 2025. Atualmente até por onde eu sei apenas LLVM/Clang tem uma implementação do _BitInt.

stdarg.h

stdarg.h define comportamentos similares ao rest parameters do javascript ou kwargs do python, uma maneira de encapsular o resto dos parâmetros de uma função não nomeados.

Exemplo sobre stdarg.h da wikipedia:

// somatório de números

#include <stdio.h>
#include <stdarg.h>

// primeiro argumento é a quantidade de valores
void somatorio(int count, ...)
{
  va_list ap;
  int i = 0;
  int soma = 0;
  va_start(ap, arg1); 
  for (i = 0; i < count; i++)
    soma += va_arg(ap, int);
  va_end(ap);
  return soma;
}

int main(void)
{
   printf("%i", somatorio(2, 1, 3));
   return 0;
}

Esse programa produz a saída:

4

stdbit.h

Tratamento e criação de novos tipos de dados primitivos parecem ser um tema para o C Moderno. Foi introduzido um completo novo módulo da biblioteca padrão para justamente trazer novas operações e utilidades para números binários. Agora vou trazer uma quote traduzida da especificação atual do C23:

O Header <stdbit.h> define macros, tipos e funções para trabalhar com a representação binária e byte de diversos tipos, tipicamente tipos inteiros. Esse header torna disponível o tipo size_t e qualquer tipo uintN_t, intN_t, uint_leastN_T, ou int_leastN_t definidos pela implementação.

Algumas de suas funcionalidades interessantes:

  • Funções para contagem de zeros/uns consecutivos no início e fim da stream;

  • Funções para verificar o primeiro e último valor de uma stream.

  • Checagem de um único bit

  • Computação do menor número de bits possível para armazenar um valor.

Imagino que funções oferecidas pelo <stdbit.h> sejam interessantes para quem trabalha com processamento de sinais, imagens ou arquivos binários.