Desafio C

Portabilidade com stdint.h e conversões seguras

Enunciado

Escreva um programa que use stdint.h para declarar variáveis de largura fixa: int8_t, uint16_t, int32_t e uint64_t. Atribua valores que exercitem os limites de cada tipo (por exemplo, INT8_MAX, UINT16_MAX, etc.). Imprima os valores e seus tamanhos com sizeof. Use os macros de limite de stdint.h para verificar se os valores estão dentro do intervalo antes de atribuir.

Requisitos

  • Incluir <stdint.h> e <stdio.h>.
  • Declarar as quatro variáveis com os tipos de largura fixa.
  • Usar macros como INT8_MAX, UINT16_MAX, INT32_MAX, UINT64_MAX para inicializar ou verificar.
  • Imprimir cada valor e seu tamanho com sizeof.

Código inicial

#include <stdio.h>
#include <stdint.h>

int main(void) {
    // Declare e inicialize as variáveis

    // Imprima valores e tamanhos

    return 0;
}

Saída esperada

int8_t: 127 (1 byte)
uint16_t: 65535 (2 bytes)
int32_t: 2147483647 (4 bytes)
uint64_t: 18446744073709551615 (8 bytes)
Ver dica

Use PRId8, PRIu16, PRId32 e PRIu64 de <inttypes.h> para imprimir corretamente. Ou faça cast para tipos maiores.

Mostrar solução
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h> // para macros de formato

int main(void) {
    // Tipos de largura fixa com valores máximos
    int8_t i8 = INT8_MAX;          // 127
    uint16_t u16 = UINT16_MAX;     // 65535
    int32_t i32 = INT32_MAX;       // 2147483647
    uint64_t u64 = UINT64_MAX;     // 18446744073709551615

    // Impressão usando macros de formato para cada tipo
    printf("int8_t: %" PRId8 " (%zu byte)\n", i8, sizeof(i8));
    printf("uint16_t: %" PRIu16 " (%zu bytes)\n", u16, sizeof(u16));
    printf("int32_t: %" PRId32 " (%zu bytes)\n", i32, sizeof(i32));
    printf("uint64_t: %" PRIu64 " (%zu bytes)\n", u64, sizeof(u64));

    // Verificação de intervalo antes de atribuir
    int64_t valor = 300;
    if (valor >= INT8_MIN && valor <= INT8_MAX) {
        int8_t seguro = (int8_t)valor;
        printf("Valor %" PRId64 " cabe em int8_t: %" PRId8 "\n", valor, seguro);
    } else {
        printf("Valor %" PRId64 " não cabe em int8_t\n", valor);
    }

    return 0;
}

Passo a passo

  1. Incluímos <stdint.h> para os tipos de largura fixa e <inttypes.h> para os macros de formato (PRId8, etc.).
  2. Declaramos int8_t i8 = INT8_MAX; — INT8_MAX é 127, o maior valor positivo de 8 bits com sinal.
  3. uint16_t u16 = UINT16_MAX; — 65535, maior valor de 16 bits sem sinal.
  4. int32_t i32 = INT32_MAX; — 2147483647, maior valor de 32 bits com sinal.
  5. uint64_t u64 = UINT64_MAX; — 18446744073709551615, maior valor de 64 bits sem sinal.
  6. Usamos printf com strings de formato concatenadas: "%" PRId8 expande para "%hhd" ou similar, garantindo o tipo correto.
  7. sizeof retorna o tamanho em bytes, impresso com %zu.
  8. Depois, mostramos uma verificação de intervalo usando INT8_MIN e INT8_MAX antes de converter um int64_t para int8_t.

Por que funciona

stdint.h define tipos com largura exata (ex.: int8_t sempre 8 bits) independentemente da plataforma. Isso evita surpresas ao portar código. Os macros INT8_MAX, UINT16_MAX, etc., fornecem os limites de cada tipo. inttypes.h define macros de formato (como PRId8) que se expandem para o especificador correto (ex.: %hhd), garantindo impressão portável. A verificação de intervalo previne overflow em conversões.

Erros comuns

  • Usar %d para int8_t: printf("%d", i8); — pode funcionar por promoção, mas o correto é %hhd ou PRId8.
  • Atribuir valor fora do intervalo: int8_t x = 200; — overflow, comportamento indefinido.
  • Esquecer de incluir <inttypes.h>: os macros PRId8 não estarão definidos.
  • Usar %lu para uint64_t: em algumas plataformas unsigned long não é 64 bits; use PRIu64.

Outra forma de resolver

Poderia usar long long e unsigned long long em vez de stdint.h, mas isso não garante largura fixa em todas as plataformas. stdint.h é a forma recomendada para código portável.

Saída esperada

int8_t: 127 (1 byte)
uint16_t: 65535 (2 bytes)
int32_t: 2147483647 (4 bytes)
uint64_t: 18446744073709551615 (8 bytes)
Valor 300 não cabe em int8_t